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_lib.h>
17251877Speter#include <apr_strings.h>
18251877Speter#include <apr_date.h>
19251877Speter
20251877Speter#include "serf.h"
21251877Speter#include "serf_bucket_util.h"
22253895Speter#include "serf_private.h"
23251877Speter
24251877Spetertypedef struct {
25251877Speter    serf_bucket_t *stream;
26251877Speter    serf_bucket_t *body;        /* Pointer to the stream wrapping the body. */
27251877Speter    serf_bucket_t *headers;     /* holds parsed headers */
28251877Speter
29251877Speter    enum {
30251877Speter        STATE_STATUS_LINE,      /* reading status line */
31251877Speter        STATE_HEADERS,          /* reading headers */
32251877Speter        STATE_BODY,             /* reading body */
33251877Speter        STATE_TRAILERS,         /* reading trailers */
34251877Speter        STATE_DONE              /* we've sent EOF */
35251877Speter    } state;
36251877Speter
37251877Speter    /* Buffer for accumulating a line from the response. */
38251877Speter    serf_linebuf_t linebuf;
39251877Speter
40251877Speter    serf_status_line sl;
41251877Speter
42251877Speter    int chunked;                /* Do we need to read trailers? */
43251877Speter    int head_req;               /* Was this a HEAD request? */
44251877Speter} response_context_t;
45251877Speter
46262339Speter/* Returns 1 if according to RFC2626 this response can have a body, 0 if it
47262339Speter   must not have a body. */
48262339Speterstatic int expect_body(response_context_t *ctx)
49262339Speter{
50262339Speter    if (ctx->head_req)
51262339Speter        return 0;
52251877Speter
53262339Speter    /* 100 Continue and 101 Switching Protocols */
54262339Speter    if (ctx->sl.code >= 100 && ctx->sl.code < 200)
55262339Speter        return 0;
56262339Speter
57262339Speter    /* 204 No Content */
58262339Speter    if (ctx->sl.code == 204)
59262339Speter        return 0;
60262339Speter
61262339Speter    /* 205? */
62262339Speter
63262339Speter    /* 304 Not Modified */
64262339Speter    if (ctx->sl.code == 304)
65262339Speter        return 0;
66262339Speter
67262339Speter    return 1;
68262339Speter}
69262339Speter
70251877Speterserf_bucket_t *serf_bucket_response_create(
71251877Speter    serf_bucket_t *stream,
72251877Speter    serf_bucket_alloc_t *allocator)
73251877Speter{
74251877Speter    response_context_t *ctx;
75251877Speter
76251877Speter    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
77251877Speter    ctx->stream = stream;
78251877Speter    ctx->body = NULL;
79251877Speter    ctx->headers = serf_bucket_headers_create(allocator);
80251877Speter    ctx->state = STATE_STATUS_LINE;
81251877Speter    ctx->chunked = 0;
82251877Speter    ctx->head_req = 0;
83251877Speter
84251877Speter    serf_linebuf_init(&ctx->linebuf);
85251877Speter
86251877Speter    return serf_bucket_create(&serf_bucket_type_response, allocator, ctx);
87251877Speter}
88251877Speter
89251877Spetervoid serf_bucket_response_set_head(
90251877Speter    serf_bucket_t *bucket)
91251877Speter{
92251877Speter    response_context_t *ctx = bucket->data;
93251877Speter
94251877Speter    ctx->head_req = 1;
95251877Speter}
96251877Speter
97251877Speterserf_bucket_t *serf_bucket_response_get_headers(
98251877Speter    serf_bucket_t *bucket)
99251877Speter{
100251877Speter    return ((response_context_t *)bucket->data)->headers;
101251877Speter}
102251877Speter
103251877Speter
104251877Speterstatic void serf_response_destroy_and_data(serf_bucket_t *bucket)
105251877Speter{
106251877Speter    response_context_t *ctx = bucket->data;
107251877Speter
108251877Speter    if (ctx->state != STATE_STATUS_LINE) {
109251877Speter        serf_bucket_mem_free(bucket->allocator, (void*)ctx->sl.reason);
110251877Speter    }
111251877Speter
112251877Speter    serf_bucket_destroy(ctx->stream);
113251877Speter    if (ctx->body != NULL)
114251877Speter        serf_bucket_destroy(ctx->body);
115251877Speter    serf_bucket_destroy(ctx->headers);
116251877Speter
117251877Speter    serf_default_destroy_and_data(bucket);
118251877Speter}
119251877Speter
120251877Speterstatic apr_status_t fetch_line(response_context_t *ctx, int acceptable)
121251877Speter{
122251877Speter    return serf_linebuf_fetch(&ctx->linebuf, ctx->stream, acceptable);
123251877Speter}
124251877Speter
125251877Speterstatic apr_status_t parse_status_line(response_context_t *ctx,
126251877Speter                                      serf_bucket_alloc_t *allocator)
127251877Speter{
128251877Speter    int res;
129251877Speter    char *reason; /* ### stupid APR interface makes this non-const */
130251877Speter
131251877Speter    /* ctx->linebuf.line should be of form: HTTP/1.1 200 OK */
132251877Speter    res = apr_date_checkmask(ctx->linebuf.line, "HTTP/#.# ###*");
133251877Speter    if (!res) {
134251877Speter        /* Not an HTTP response?  Well, at least we won't understand it. */
135251877Speter        return SERF_ERROR_BAD_HTTP_RESPONSE;
136251877Speter    }
137251877Speter
138251877Speter    ctx->sl.version = SERF_HTTP_VERSION(ctx->linebuf.line[5] - '0',
139251877Speter                                        ctx->linebuf.line[7] - '0');
140251877Speter    ctx->sl.code = apr_strtoi64(ctx->linebuf.line + 8, &reason, 10);
141251877Speter
142251877Speter    /* Skip leading spaces for the reason string. */
143251877Speter    if (apr_isspace(*reason)) {
144251877Speter        reason++;
145251877Speter    }
146251877Speter
147251877Speter    /* Copy the reason value out of the line buffer. */
148251877Speter    ctx->sl.reason = serf_bstrmemdup(allocator, reason,
149251877Speter                                     ctx->linebuf.used
150251877Speter                                     - (reason - ctx->linebuf.line));
151251877Speter
152251877Speter    return APR_SUCCESS;
153251877Speter}
154251877Speter
155251877Speter/* This code should be replaced with header buckets. */
156251877Speterstatic apr_status_t fetch_headers(serf_bucket_t *bkt, response_context_t *ctx)
157251877Speter{
158251877Speter    apr_status_t status;
159251877Speter
160251877Speter    /* RFC 2616 says that CRLF is the only line ending, but we can easily
161251877Speter     * accept any kind of line ending.
162251877Speter     */
163251877Speter    status = fetch_line(ctx, SERF_NEWLINE_ANY);
164251877Speter    if (SERF_BUCKET_READ_ERROR(status)) {
165251877Speter        return status;
166251877Speter    }
167251877Speter    /* Something was read. Process it. */
168251877Speter
169251877Speter    if (ctx->linebuf.state == SERF_LINEBUF_READY && ctx->linebuf.used) {
170251877Speter        const char *end_key;
171251877Speter        const char *c;
172251877Speter
173251877Speter        end_key = c = memchr(ctx->linebuf.line, ':', ctx->linebuf.used);
174251877Speter        if (!c) {
175251877Speter            /* Bad headers? */
176251877Speter            return SERF_ERROR_BAD_HTTP_RESPONSE;
177251877Speter        }
178251877Speter
179251877Speter        /* Skip over initial ':' */
180251877Speter        c++;
181251877Speter
182251877Speter        /* And skip all whitespaces. */
183251877Speter        for(; c < ctx->linebuf.line + ctx->linebuf.used; c++)
184251877Speter        {
185251877Speter            if (!apr_isspace(*c))
186251877Speter            {
187251877Speter              break;
188251877Speter            }
189251877Speter        }
190251877Speter
191251877Speter        /* Always copy the headers (from the linebuf into new mem). */
192251877Speter        /* ### we should be able to optimize some mem copies */
193251877Speter        serf_bucket_headers_setx(
194251877Speter            ctx->headers,
195251877Speter            ctx->linebuf.line, end_key - ctx->linebuf.line, 1,
196251877Speter            c, ctx->linebuf.line + ctx->linebuf.used - c, 1);
197251877Speter    }
198251877Speter
199251877Speter    return status;
200251877Speter}
201251877Speter
202251877Speter/* Perform one iteration of the state machine.
203251877Speter *
204251877Speter * Will return when one the following conditions occurred:
205251877Speter *  1) a state change
206251877Speter *  2) an error
207251877Speter *  3) the stream is not ready or at EOF
208251877Speter *  4) APR_SUCCESS, meaning the machine can be run again immediately
209251877Speter */
210251877Speterstatic apr_status_t run_machine(serf_bucket_t *bkt, response_context_t *ctx)
211251877Speter{
212251877Speter    apr_status_t status = APR_SUCCESS; /* initialize to avoid gcc warnings */
213251877Speter
214251877Speter    switch (ctx->state) {
215251877Speter    case STATE_STATUS_LINE:
216251877Speter        /* RFC 2616 says that CRLF is the only line ending, but we can easily
217251877Speter         * accept any kind of line ending.
218251877Speter         */
219251877Speter        status = fetch_line(ctx, SERF_NEWLINE_ANY);
220251877Speter        if (SERF_BUCKET_READ_ERROR(status))
221251877Speter            return status;
222251877Speter
223251877Speter        if (ctx->linebuf.state == SERF_LINEBUF_READY) {
224251877Speter            /* The Status-Line is in the line buffer. Process it. */
225251877Speter            status = parse_status_line(ctx, bkt->allocator);
226251877Speter            if (status)
227251877Speter                return status;
228251877Speter
229251877Speter            /* Good times ahead: we're switching protocols! */
230251877Speter            if (ctx->sl.code == 101) {
231251877Speter                ctx->body =
232251877Speter                    serf_bucket_barrier_create(ctx->stream, bkt->allocator);
233251877Speter                ctx->state = STATE_DONE;
234251877Speter                break;
235251877Speter            }
236251877Speter
237251877Speter            /* Okay... move on to reading the headers. */
238251877Speter            ctx->state = STATE_HEADERS;
239251877Speter        }
240251877Speter        else {
241251877Speter            /* The connection closed before we could get the next
242251877Speter             * response.  Treat the request as lost so that our upper
243251877Speter             * end knows the server never tried to give us a response.
244251877Speter             */
245251877Speter            if (APR_STATUS_IS_EOF(status)) {
246251877Speter                return SERF_ERROR_REQUEST_LOST;
247251877Speter            }
248251877Speter        }
249251877Speter        break;
250251877Speter    case STATE_HEADERS:
251251877Speter        status = fetch_headers(bkt, ctx);
252251877Speter        if (SERF_BUCKET_READ_ERROR(status))
253251877Speter            return status;
254251877Speter
255251877Speter        /* If an empty line was read, then we hit the end of the headers.
256251877Speter         * Move on to the body.
257251877Speter         */
258251877Speter        if (ctx->linebuf.state == SERF_LINEBUF_READY && !ctx->linebuf.used) {
259251877Speter            const void *v;
260251877Speter
261251877Speter            /* Advance the state. */
262251877Speter            ctx->state = STATE_BODY;
263251877Speter
264262339Speter            /* If this is a response to a HEAD request, or code == 1xx,204 or304
265262339Speter               then we don't receive a real body. */
266262339Speter            if (!expect_body(ctx)) {
267262339Speter                ctx->body = serf_bucket_simple_create(NULL, 0, NULL, NULL,
268262339Speter                                                      bkt->allocator);
269262339Speter                ctx->state = STATE_BODY;
270262339Speter                break;
271262339Speter            }
272262339Speter
273251877Speter            ctx->body =
274251877Speter                serf_bucket_barrier_create(ctx->stream, bkt->allocator);
275251877Speter
276251877Speter            /* Are we C-L, chunked, or conn close? */
277251877Speter            v = serf_bucket_headers_get(ctx->headers, "Content-Length");
278251877Speter            if (v) {
279251877Speter                apr_uint64_t length;
280251877Speter                length = apr_strtoi64(v, NULL, 10);
281251877Speter                if (errno == ERANGE) {
282251877Speter                    return APR_FROM_OS_ERROR(ERANGE);
283251877Speter                }
284251877Speter                ctx->body = serf_bucket_response_body_create(
285251877Speter                              ctx->body, length, bkt->allocator);
286251877Speter            }
287251877Speter            else {
288251877Speter                v = serf_bucket_headers_get(ctx->headers, "Transfer-Encoding");
289251877Speter
290251877Speter                /* Need to handle multiple transfer-encoding. */
291251877Speter                if (v && strcasecmp("chunked", v) == 0) {
292251877Speter                    ctx->chunked = 1;
293251877Speter                    ctx->body = serf_bucket_dechunk_create(ctx->body,
294251877Speter                                                           bkt->allocator);
295251877Speter                }
296251877Speter            }
297251877Speter            v = serf_bucket_headers_get(ctx->headers, "Content-Encoding");
298251877Speter            if (v) {
299251877Speter                /* Need to handle multiple content-encoding. */
300251877Speter                if (v && strcasecmp("gzip", v) == 0) {
301251877Speter                    ctx->body =
302251877Speter                        serf_bucket_deflate_create(ctx->body, bkt->allocator,
303251877Speter                                                   SERF_DEFLATE_GZIP);
304251877Speter                }
305251877Speter                else if (v && strcasecmp("deflate", v) == 0) {
306251877Speter                    ctx->body =
307251877Speter                        serf_bucket_deflate_create(ctx->body, bkt->allocator,
308251877Speter                                                   SERF_DEFLATE_DEFLATE);
309251877Speter                }
310251877Speter            }
311251877Speter        }
312251877Speter        break;
313251877Speter    case STATE_BODY:
314251877Speter        /* Don't do anything. */
315251877Speter        break;
316251877Speter    case STATE_TRAILERS:
317251877Speter        status = fetch_headers(bkt, ctx);
318251877Speter        if (SERF_BUCKET_READ_ERROR(status))
319251877Speter            return status;
320251877Speter
321251877Speter        /* If an empty line was read, then we're done. */
322251877Speter        if (ctx->linebuf.state == SERF_LINEBUF_READY && !ctx->linebuf.used) {
323251877Speter            ctx->state = STATE_DONE;
324251877Speter            return APR_EOF;
325251877Speter        }
326251877Speter        break;
327251877Speter    case STATE_DONE:
328251877Speter        return APR_EOF;
329251877Speter    default:
330251877Speter        /* Not reachable */
331251877Speter        return APR_EGENERAL;
332251877Speter    }
333251877Speter
334251877Speter    return status;
335251877Speter}
336251877Speter
337251877Speterstatic apr_status_t wait_for_body(serf_bucket_t *bkt, response_context_t *ctx)
338251877Speter{
339251877Speter    apr_status_t status;
340251877Speter
341251877Speter    /* Keep reading and moving through states if we aren't at the BODY */
342251877Speter    while (ctx->state != STATE_BODY) {
343251877Speter        status = run_machine(bkt, ctx);
344251877Speter
345251877Speter        /* Anything other than APR_SUCCESS means that we cannot immediately
346251877Speter         * read again (for now).
347251877Speter         */
348251877Speter        if (status)
349251877Speter            return status;
350251877Speter    }
351251877Speter    /* in STATE_BODY */
352251877Speter
353251877Speter    return APR_SUCCESS;
354251877Speter}
355251877Speter
356251877Speterapr_status_t serf_bucket_response_wait_for_headers(
357251877Speter    serf_bucket_t *bucket)
358251877Speter{
359251877Speter    response_context_t *ctx = bucket->data;
360251877Speter
361251877Speter    return wait_for_body(bucket, ctx);
362251877Speter}
363251877Speter
364251877Speterapr_status_t serf_bucket_response_status(
365251877Speter    serf_bucket_t *bkt,
366251877Speter    serf_status_line *sline)
367251877Speter{
368251877Speter    response_context_t *ctx = bkt->data;
369251877Speter    apr_status_t status;
370251877Speter
371251877Speter    if (ctx->state != STATE_STATUS_LINE) {
372251877Speter        /* We already read it and moved on. Just return it. */
373251877Speter        *sline = ctx->sl;
374251877Speter        return APR_SUCCESS;
375251877Speter    }
376251877Speter
377251877Speter    /* Running the state machine once will advance the machine, or state
378251877Speter     * that the stream isn't ready with enough data. There isn't ever a
379251877Speter     * need to run the machine more than once to try and satisfy this. We
380251877Speter     * have to look at the state to tell whether it advanced, though, as
381251877Speter     * it is quite possible to advance *and* to return APR_EAGAIN.
382251877Speter     */
383251877Speter    status = run_machine(bkt, ctx);
384251877Speter    if (ctx->state == STATE_HEADERS) {
385251877Speter        *sline = ctx->sl;
386251877Speter    }
387251877Speter    else {
388251877Speter        /* Indicate that we don't have the information yet. */
389251877Speter        sline->version = 0;
390251877Speter    }
391251877Speter
392251877Speter    return status;
393251877Speter}
394251877Speter
395251877Speterstatic apr_status_t serf_response_read(serf_bucket_t *bucket,
396251877Speter                                       apr_size_t requested,
397251877Speter                                       const char **data, apr_size_t *len)
398251877Speter{
399251877Speter    response_context_t *ctx = bucket->data;
400251877Speter    apr_status_t rv;
401251877Speter
402251877Speter    rv = wait_for_body(bucket, ctx);
403251877Speter    if (rv) {
404251877Speter        /* It's not possible to have read anything yet! */
405251877Speter        if (APR_STATUS_IS_EOF(rv) || APR_STATUS_IS_EAGAIN(rv)) {
406251877Speter            *len = 0;
407251877Speter        }
408251877Speter        return rv;
409251877Speter    }
410251877Speter
411251877Speter    rv = serf_bucket_read(ctx->body, requested, data, len);
412251877Speter    if (SERF_BUCKET_READ_ERROR(rv))
413251877Speter        return rv;
414251877Speter
415251877Speter    if (APR_STATUS_IS_EOF(rv)) {
416251877Speter        if (ctx->chunked) {
417251877Speter            ctx->state = STATE_TRAILERS;
418251877Speter            /* Mask the result. */
419251877Speter            rv = APR_SUCCESS;
420251877Speter        } else {
421251877Speter            ctx->state = STATE_DONE;
422251877Speter        }
423251877Speter    }
424251877Speter    return rv;
425251877Speter}
426251877Speter
427251877Speterstatic apr_status_t serf_response_readline(serf_bucket_t *bucket,
428251877Speter                                           int acceptable, int *found,
429251877Speter                                           const char **data, apr_size_t *len)
430251877Speter{
431251877Speter    response_context_t *ctx = bucket->data;
432251877Speter    apr_status_t rv;
433251877Speter
434251877Speter    rv = wait_for_body(bucket, ctx);
435251877Speter    if (rv) {
436251877Speter        return rv;
437251877Speter    }
438251877Speter
439251877Speter    /* Delegate to the stream bucket to do the readline. */
440251877Speter    return serf_bucket_readline(ctx->body, acceptable, found, data, len);
441251877Speter}
442251877Speter
443251877Speterapr_status_t serf_response_full_become_aggregate(serf_bucket_t *bucket)
444251877Speter{
445251877Speter    response_context_t *ctx = bucket->data;
446251877Speter    serf_bucket_t *bkt;
447251877Speter    char buf[256];
448251877Speter    int size;
449251877Speter
450251877Speter    serf_bucket_aggregate_become(bucket);
451251877Speter
452251877Speter    /* Add reconstructed status line. */
453251877Speter    size = apr_snprintf(buf, 256, "HTTP/%d.%d %d ",
454251877Speter                        SERF_HTTP_VERSION_MAJOR(ctx->sl.version),
455251877Speter                        SERF_HTTP_VERSION_MINOR(ctx->sl.version),
456251877Speter                        ctx->sl.code);
457251877Speter    bkt = serf_bucket_simple_copy_create(buf, size,
458251877Speter                                         bucket->allocator);
459251877Speter    serf_bucket_aggregate_append(bucket, bkt);
460251877Speter    bkt = serf_bucket_simple_copy_create(ctx->sl.reason, strlen(ctx->sl.reason),
461251877Speter                                         bucket->allocator);
462251877Speter    serf_bucket_aggregate_append(bucket, bkt);
463251877Speter    bkt = SERF_BUCKET_SIMPLE_STRING_LEN("\r\n", 2,
464251877Speter                                        bucket->allocator);
465251877Speter    serf_bucket_aggregate_append(bucket, bkt);
466251877Speter
467251877Speter    /* Add headers and stream buckets in order. */
468251877Speter    serf_bucket_aggregate_append(bucket, ctx->headers);
469251877Speter    serf_bucket_aggregate_append(bucket, ctx->stream);
470251877Speter
471251877Speter    serf_bucket_mem_free(bucket->allocator, ctx);
472251877Speter
473251877Speter    return APR_SUCCESS;
474251877Speter}
475251877Speter
476251877Speter/* ### need to implement */
477251877Speter#define serf_response_peek NULL
478251877Speter
479251877Speterconst serf_bucket_type_t serf_bucket_type_response = {
480251877Speter    "RESPONSE",
481251877Speter    serf_response_read,
482251877Speter    serf_response_readline,
483251877Speter    serf_default_read_iovec,
484251877Speter    serf_default_read_for_sendfile,
485251877Speter    serf_default_read_bucket,
486251877Speter    serf_response_peek,
487251877Speter    serf_response_destroy_and_data,
488251877Speter};
489