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