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