1251877Speter/* Copyright 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 <stdlib.h>
17251877Speter
18251877Speter#include <apr_general.h>  /* for strcasecmp() */
19251877Speter
20251877Speter#include "serf.h"
21251877Speter#include "serf_bucket_util.h"
22251877Speter
23251877Speter
24251877Spetertypedef struct header_list {
25251877Speter    const char *header;
26251877Speter    const char *value;
27251877Speter
28251877Speter    apr_size_t header_size;
29251877Speter    apr_size_t value_size;
30251877Speter
31251877Speter    int alloc_flags;
32251877Speter#define ALLOC_HEADER 0x0001  /* header lives in our allocator */
33251877Speter#define ALLOC_VALUE  0x0002  /* value lives in our allocator */
34251877Speter
35251877Speter    struct header_list *next;
36251877Speter} header_list_t;
37251877Speter
38251877Spetertypedef struct {
39251877Speter    header_list_t *list;
40251877Speter
41251877Speter    header_list_t *cur_read;
42251877Speter    enum {
43251877Speter        READ_START,     /* haven't started reading yet */
44251877Speter        READ_HEADER,    /* reading cur_read->header */
45251877Speter        READ_SEP,       /* reading ": " */
46251877Speter        READ_VALUE,     /* reading cur_read->value */
47251877Speter        READ_CRLF,      /* reading "\r\n" */
48251877Speter        READ_TERM,      /* reading the final "\r\n" */
49251877Speter        READ_DONE       /* no more data to read */
50251877Speter    } state;
51251877Speter    apr_size_t amt_read; /* how much of the current state we've read */
52251877Speter
53251877Speter} headers_context_t;
54251877Speter
55251877Speter
56251877Speterserf_bucket_t *serf_bucket_headers_create(
57251877Speter    serf_bucket_alloc_t *allocator)
58251877Speter{
59251877Speter    headers_context_t *ctx;
60251877Speter
61251877Speter    ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
62251877Speter    ctx->list = NULL;
63251877Speter    ctx->state = READ_START;
64251877Speter
65251877Speter    return serf_bucket_create(&serf_bucket_type_headers, allocator, ctx);
66251877Speter}
67251877Speter
68251877Spetervoid serf_bucket_headers_setx(
69251877Speter    serf_bucket_t *bkt,
70251877Speter    const char *header, apr_size_t header_size, int header_copy,
71251877Speter    const char *value, apr_size_t value_size, int value_copy)
72251877Speter{
73251877Speter    headers_context_t *ctx = bkt->data;
74251877Speter    header_list_t *iter = ctx->list;
75251877Speter    header_list_t *hdr;
76251877Speter
77251877Speter#if 0
78251877Speter    /* ### include this? */
79251877Speter    if (ctx->cur_read) {
80251877Speter        /* we started reading. can't change now. */
81251877Speter        abort();
82251877Speter    }
83251877Speter#endif
84251877Speter
85251877Speter    hdr = serf_bucket_mem_alloc(bkt->allocator, sizeof(*hdr));
86251877Speter    hdr->header_size = header_size;
87251877Speter    hdr->value_size = value_size;
88251877Speter    hdr->alloc_flags = 0;
89251877Speter    hdr->next = NULL;
90251877Speter
91251877Speter    if (header_copy) {
92251877Speter        hdr->header = serf_bstrmemdup(bkt->allocator, header, header_size);
93251877Speter        hdr->alloc_flags |= ALLOC_HEADER;
94251877Speter    }
95251877Speter    else {
96251877Speter        hdr->header = header;
97251877Speter    }
98251877Speter
99251877Speter    if (value_copy) {
100251877Speter        hdr->value = serf_bstrmemdup(bkt->allocator, value, value_size);
101251877Speter        hdr->alloc_flags |= ALLOC_VALUE;
102251877Speter    }
103251877Speter    else {
104251877Speter        hdr->value = value;
105251877Speter    }
106251877Speter
107251877Speter    /* Add the new header at the end of the list. */
108251877Speter    while (iter && iter->next) {
109251877Speter        iter = iter->next;
110251877Speter    }
111251877Speter    if (iter)
112251877Speter        iter->next = hdr;
113251877Speter    else
114251877Speter        ctx->list = hdr;
115251877Speter}
116251877Speter
117251877Spetervoid serf_bucket_headers_set(
118251877Speter    serf_bucket_t *headers_bucket,
119251877Speter    const char *header,
120251877Speter    const char *value)
121251877Speter{
122251877Speter    serf_bucket_headers_setx(headers_bucket,
123251877Speter                             header, strlen(header), 0,
124251877Speter                             value, strlen(value), 1);
125251877Speter}
126251877Speter
127251877Spetervoid serf_bucket_headers_setc(
128251877Speter    serf_bucket_t *headers_bucket,
129251877Speter    const char *header,
130251877Speter    const char *value)
131251877Speter{
132251877Speter    serf_bucket_headers_setx(headers_bucket,
133251877Speter                             header, strlen(header), 1,
134251877Speter                             value, strlen(value), 1);
135251877Speter}
136251877Speter
137251877Spetervoid serf_bucket_headers_setn(
138251877Speter    serf_bucket_t *headers_bucket,
139251877Speter    const char *header,
140251877Speter    const char *value)
141251877Speter{
142251877Speter    serf_bucket_headers_setx(headers_bucket,
143251877Speter                             header, strlen(header), 0,
144251877Speter                             value, strlen(value), 0);
145251877Speter}
146251877Speter
147251877Speterconst char *serf_bucket_headers_get(
148251877Speter    serf_bucket_t *headers_bucket,
149251877Speter    const char *header)
150251877Speter{
151251877Speter    headers_context_t *ctx = headers_bucket->data;
152251877Speter    header_list_t *found = ctx->list;
153251877Speter    const char *val = NULL;
154251877Speter    int value_size = 0;
155251877Speter    int val_alloc = 0;
156251877Speter
157251877Speter    while (found) {
158251877Speter        if (strcasecmp(found->header, header) == 0) {
159251877Speter            if (val) {
160251877Speter                /* The header is already present.  RFC 2616, section 4.2
161251877Speter                   indicates that we should append the new value, separated by
162251877Speter                   a comma.  Reasoning: for headers whose values are known to
163251877Speter                   be comma-separated, that is clearly the correct behavior;
164251877Speter                   for others, the correct behavior is undefined anyway. */
165251877Speter
166251877Speter                /* The "+1" is for the comma; the +1 in the alloc
167251877Speter                   call is for the terminating '\0' */
168251877Speter                apr_size_t new_size = found->value_size + value_size + 1;
169251877Speter                char *new_val = serf_bucket_mem_alloc(headers_bucket->allocator,
170251877Speter                                                      new_size + 1);
171251877Speter                memcpy(new_val, val, value_size);
172251877Speter                new_val[value_size] = ',';
173251877Speter                memcpy(new_val + value_size + 1, found->value,
174251877Speter                       found->value_size);
175251877Speter                new_val[new_size] = '\0';
176251877Speter                /* Copy the new value over the already existing value. */
177251877Speter                if (val_alloc)
178251877Speter                    serf_bucket_mem_free(headers_bucket->allocator, (void*)val);
179251877Speter                val_alloc |= ALLOC_VALUE;
180251877Speter                val = new_val;
181251877Speter                value_size = new_size;
182251877Speter            }
183251877Speter            else {
184251877Speter                val = found->value;
185251877Speter                value_size = found->value_size;
186251877Speter            }
187251877Speter        }
188251877Speter        found = found->next;
189251877Speter    }
190251877Speter
191251877Speter    return val;
192251877Speter}
193251877Speter
194251877Spetervoid serf_bucket_headers_do(
195251877Speter    serf_bucket_t *headers_bucket,
196251877Speter    serf_bucket_headers_do_callback_fn_t func,
197251877Speter    void *baton)
198251877Speter{
199251877Speter    headers_context_t *ctx = headers_bucket->data;
200251877Speter    header_list_t *scan = ctx->list;
201251877Speter
202251877Speter    while (scan) {
203251877Speter        if (func(baton, scan->header, scan->value) != 0) {
204251877Speter            break;
205251877Speter        }
206251877Speter        scan = scan->next;
207251877Speter    }
208251877Speter}
209251877Speter
210251877Speterstatic void serf_headers_destroy_and_data(serf_bucket_t *bucket)
211251877Speter{
212251877Speter    headers_context_t *ctx = bucket->data;
213251877Speter    header_list_t *scan = ctx->list;
214251877Speter
215251877Speter    while (scan) {
216251877Speter        header_list_t *next_hdr = scan->next;
217251877Speter
218251877Speter        if (scan->alloc_flags & ALLOC_HEADER)
219251877Speter            serf_bucket_mem_free(bucket->allocator, (void *)scan->header);
220251877Speter        if (scan->alloc_flags & ALLOC_VALUE)
221251877Speter            serf_bucket_mem_free(bucket->allocator, (void *)scan->value);
222251877Speter        serf_bucket_mem_free(bucket->allocator, scan);
223251877Speter
224251877Speter        scan = next_hdr;
225251877Speter    }
226251877Speter
227251877Speter    serf_default_destroy_and_data(bucket);
228251877Speter}
229251877Speter
230251877Speterstatic void select_value(
231251877Speter    headers_context_t *ctx,
232251877Speter    const char **value,
233251877Speter    apr_size_t *len)
234251877Speter{
235251877Speter    const char *v;
236251877Speter    apr_size_t l;
237251877Speter
238251877Speter    if (ctx->state == READ_START) {
239251877Speter        if (ctx->list == NULL) {
240251877Speter            /* No headers. Move straight to the TERM state. */
241251877Speter            ctx->state = READ_TERM;
242251877Speter        }
243251877Speter        else {
244251877Speter            ctx->state = READ_HEADER;
245251877Speter            ctx->cur_read = ctx->list;
246251877Speter        }
247251877Speter        ctx->amt_read = 0;
248251877Speter    }
249251877Speter
250251877Speter    switch (ctx->state) {
251251877Speter    case READ_HEADER:
252251877Speter        v = ctx->cur_read->header;
253251877Speter        l = ctx->cur_read->header_size;
254251877Speter        break;
255251877Speter    case READ_SEP:
256251877Speter        v = ": ";
257251877Speter        l = 2;
258251877Speter        break;
259251877Speter    case READ_VALUE:
260251877Speter        v = ctx->cur_read->value;
261251877Speter        l = ctx->cur_read->value_size;
262251877Speter        break;
263251877Speter    case READ_CRLF:
264251877Speter    case READ_TERM:
265251877Speter        v = "\r\n";
266251877Speter        l = 2;
267251877Speter        break;
268251877Speter    case READ_DONE:
269251877Speter        *len = 0;
270251877Speter        return;
271251877Speter    default:
272251877Speter        /* Not reachable */
273251877Speter        return;
274251877Speter    }
275251877Speter
276251877Speter    *value = v + ctx->amt_read;
277251877Speter    *len = l - ctx->amt_read;
278251877Speter}
279251877Speter
280251877Speter/* the current data chunk has been read/consumed. move our internal state. */
281251877Speterstatic apr_status_t consume_chunk(headers_context_t *ctx)
282251877Speter{
283251877Speter    /* move to the next state, resetting the amount read. */
284251877Speter    ++ctx->state;
285251877Speter    ctx->amt_read = 0;
286251877Speter
287251877Speter    /* just sent the terminator and moved to DONE. signal completion. */
288251877Speter    if (ctx->state == READ_DONE)
289251877Speter        return APR_EOF;
290251877Speter
291251877Speter    /* end of this header. move to the next one. */
292251877Speter    if (ctx->state == READ_TERM) {
293251877Speter        ctx->cur_read = ctx->cur_read->next;
294251877Speter        if (ctx->cur_read != NULL) {
295251877Speter            /* We've got another head to send. Reset the read state. */
296251877Speter            ctx->state = READ_HEADER;
297251877Speter        }
298251877Speter        /* else leave in READ_TERM */
299251877Speter    }
300251877Speter
301251877Speter    /* there is more data which can be read immediately. */
302251877Speter    return APR_SUCCESS;
303251877Speter}
304251877Speter
305251877Speterstatic apr_status_t serf_headers_peek(serf_bucket_t *bucket,
306251877Speter                                      const char **data,
307251877Speter                                      apr_size_t *len)
308251877Speter{
309251877Speter    headers_context_t *ctx = bucket->data;
310251877Speter
311251877Speter    select_value(ctx, data, len);
312251877Speter
313251877Speter    /* already done or returning the CRLF terminator? return EOF */
314251877Speter    if (ctx->state == READ_DONE || ctx->state == READ_TERM)
315251877Speter        return APR_EOF;
316251877Speter
317251877Speter    return APR_SUCCESS;
318251877Speter}
319251877Speter
320251877Speterstatic apr_status_t serf_headers_read(serf_bucket_t *bucket,
321251877Speter                                      apr_size_t requested,
322251877Speter                                      const char **data, apr_size_t *len)
323251877Speter{
324251877Speter    headers_context_t *ctx = bucket->data;
325251877Speter    apr_size_t avail;
326251877Speter
327251877Speter    select_value(ctx, data, &avail);
328253895Speter    if (ctx->state == READ_DONE) {
329253895Speter        *len = avail;
330251877Speter        return APR_EOF;
331253895Speter    }
332251877Speter
333251877Speter    if (requested >= avail) {
334251877Speter        /* return everything from this chunk */
335251877Speter        *len = avail;
336251877Speter
337251877Speter        /* we consumed this chunk. advance the state. */
338251877Speter        return consume_chunk(ctx);
339251877Speter    }
340251877Speter
341251877Speter    /* return just the amount requested, and advance our pointer */
342251877Speter    *len = requested;
343251877Speter    ctx->amt_read += requested;
344251877Speter
345251877Speter    /* there is more that can be read immediately */
346251877Speter    return APR_SUCCESS;
347251877Speter}
348251877Speter
349251877Speterstatic apr_status_t serf_headers_readline(serf_bucket_t *bucket,
350251877Speter                                          int acceptable, int *found,
351251877Speter                                          const char **data, apr_size_t *len)
352251877Speter{
353251877Speter    headers_context_t *ctx = bucket->data;
354251877Speter    apr_status_t status;
355251877Speter
356251877Speter    /* ### what behavior should we use here? APR_EGENERAL for now */
357251877Speter    if ((acceptable & SERF_NEWLINE_CRLF) == 0)
358251877Speter        return APR_EGENERAL;
359251877Speter
360251877Speter    /* get whatever is in this chunk */
361251877Speter    select_value(ctx, data, len);
362251877Speter    if (ctx->state == READ_DONE)
363251877Speter        return APR_EOF;
364251877Speter
365251877Speter    /* we consumed this chunk. advance the state. */
366251877Speter    status = consume_chunk(ctx);
367251877Speter
368251877Speter    /* the type of newline found is easy... */
369251877Speter    *found = (ctx->state == READ_CRLF || ctx->state == READ_TERM)
370251877Speter        ? SERF_NEWLINE_CRLF : SERF_NEWLINE_NONE;
371251877Speter
372251877Speter    return status;
373251877Speter}
374251877Speter
375251877Speterstatic apr_status_t serf_headers_read_iovec(serf_bucket_t *bucket,
376251877Speter                                            apr_size_t requested,
377251877Speter                                            int vecs_size,
378251877Speter                                            struct iovec *vecs,
379251877Speter                                            int *vecs_used)
380251877Speter{
381251877Speter    apr_size_t avail = requested;
382251877Speter    int i;
383251877Speter
384251877Speter    *vecs_used = 0;
385251877Speter
386251877Speter    for (i = 0; i < vecs_size; i++) {
387251877Speter        const char *data;
388251877Speter        apr_size_t len;
389251877Speter        apr_status_t status;
390251877Speter
391251877Speter        /* Calling read() would not be a safe opt in the general case, but it
392251877Speter         * is here for the header bucket as it only frees all of the header
393251877Speter         * keys and values when the entire bucket goes away - not on a
394251877Speter         * per-read() basis as is normally the case.
395251877Speter         */
396251877Speter        status = serf_headers_read(bucket, avail, &data, &len);
397251877Speter
398251877Speter        if (len) {
399251877Speter            vecs[*vecs_used].iov_base = (char*)data;
400251877Speter            vecs[*vecs_used].iov_len = len;
401251877Speter
402251877Speter            (*vecs_used)++;
403251877Speter
404251877Speter            if (avail != SERF_READ_ALL_AVAIL) {
405251877Speter                avail -= len;
406251877Speter
407251877Speter                /* If we reach 0, then read()'s status will suffice.  */
408251877Speter                if (avail == 0) {
409251877Speter                    return status;
410251877Speter                }
411251877Speter            }
412251877Speter        }
413251877Speter
414251877Speter        if (status) {
415251877Speter            return status;
416251877Speter        }
417251877Speter    }
418251877Speter
419251877Speter    return APR_SUCCESS;
420251877Speter}
421251877Speter
422251877Speterconst serf_bucket_type_t serf_bucket_type_headers = {
423251877Speter    "HEADERS",
424251877Speter    serf_headers_read,
425251877Speter    serf_headers_readline,
426251877Speter    serf_headers_read_iovec,
427251877Speter    serf_default_read_for_sendfile,
428251877Speter    serf_default_read_bucket,
429251877Speter    serf_headers_peek,
430251877Speter    serf_headers_destroy_and_data,
431251877Speter};
432