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