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