request_buckets.c revision 296373
1218893Sdim/* Copyright 2002-2004 Justin Erenkrantz and Greg Stein 2212793Sdim * 3212793Sdim * Licensed under the Apache License, Version 2.0 (the "License"); 4212793Sdim * you may not use this file except in compliance with the License. 5212793Sdim * You may obtain a copy of the License at 6212793Sdim * 7212793Sdim * http://www.apache.org/licenses/LICENSE-2.0 8212793Sdim * 9212793Sdim * Unless required by applicable law or agreed to in writing, software 10212793Sdim * distributed under the License is distributed on an "AS IS" BASIS, 11212793Sdim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12212793Sdim * See the License for the specific language governing permissions and 13212793Sdim * limitations under the License. 14212793Sdim */ 15221345Sdim 16221345Sdim#include <apr_pools.h> 17221345Sdim#include <apr_strings.h> 18226633Sdim 19221345Sdim#include "serf.h" 20218893Sdim#include "serf_bucket_util.h" 21218893Sdim 22212793Sdim 23212793Sdimtypedef struct { 24212793Sdim const char *method; 25212793Sdim const char *uri; 26218893Sdim serf_bucket_t *headers; 27212793Sdim serf_bucket_t *body; 28212793Sdim apr_int64_t len; 29218893Sdim} request_context_t; 30263508Sdim 31212793Sdim#define LENGTH_UNKNOWN ((apr_int64_t)-1) 32212793Sdim 33212793Sdim 34212793Sdimserf_bucket_t *serf_bucket_request_create( 35218893Sdim const char *method, 36212793Sdim const char *URI, 37212793Sdim serf_bucket_t *body, 38218893Sdim serf_bucket_alloc_t *allocator) 39212793Sdim{ 40212793Sdim request_context_t *ctx; 41212793Sdim 42212793Sdim ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx)); 43212793Sdim ctx->method = method; 44218893Sdim ctx->uri = URI; 45218893Sdim ctx->headers = serf_bucket_headers_create(allocator); 46218893Sdim ctx->body = body; 47218893Sdim ctx->len = LENGTH_UNKNOWN; 48218893Sdim 49212793Sdim return serf_bucket_create(&serf_bucket_type_request, allocator, ctx); 50218893Sdim} 51218893Sdim 52218893Sdimvoid serf_bucket_request_set_CL( 53218893Sdim serf_bucket_t *bucket, 54218893Sdim apr_int64_t len) 55218893Sdim{ 56223017Sdim request_context_t *ctx = (request_context_t *)bucket->data; 57218893Sdim 58223017Sdim ctx->len = len; 59218893Sdim} 60223017Sdim 61223017Sdimserf_bucket_t *serf_bucket_request_get_headers( 62223017Sdim serf_bucket_t *bucket) 63223017Sdim{ 64223017Sdim return ((request_context_t *)bucket->data)->headers; 65223017Sdim} 66223017Sdim 67218893Sdimvoid serf_bucket_request_set_root( 68218893Sdim serf_bucket_t *bucket, 69226633Sdim const char *root_url) 70226633Sdim{ 71226633Sdim request_context_t *ctx = (request_context_t *)bucket->data; 72218893Sdim 73218893Sdim /* If uri is already absolute, don't change it. */ 74224145Sdim if (ctx->uri[0] != '/') 75224145Sdim return; 76224145Sdim 77224145Sdim /* If uri is '/' replace it with root_url. */ 78226633Sdim if (ctx->uri[1] == '\0') 79224145Sdim ctx->uri = root_url; 80218893Sdim else 81218893Sdim ctx->uri = 82212793Sdim apr_pstrcat(serf_bucket_allocator_get_pool(bucket->allocator), 83212793Sdim root_url, 84218893Sdim ctx->uri, 85212793Sdim NULL); 86234353Sdim} 87234353Sdim 88234353Sdimstatic void serialize_data(serf_bucket_t *bucket) 89221345Sdim{ 90221345Sdim request_context_t *ctx = bucket->data; 91221345Sdim serf_bucket_t *new_bucket; 92221345Sdim const char *new_data; 93221345Sdim struct iovec iov[4]; 94221345Sdim apr_size_t nbytes; 95221345Sdim 96221345Sdim /* Serialize the request-line and headers into one mother string, 97221345Sdim * and wrap a bucket around it. 98223017Sdim */ 99223017Sdim iov[0].iov_base = (char*)ctx->method; 100223017Sdim iov[0].iov_len = strlen(ctx->method); 101223017Sdim iov[1].iov_base = " "; 102221345Sdim iov[1].iov_len = sizeof(" ") - 1; 103221345Sdim iov[2].iov_base = (char*)ctx->uri; 104221345Sdim iov[2].iov_len = strlen(ctx->uri); 105221345Sdim iov[3].iov_base = " HTTP/1.1\r\n"; 106221345Sdim iov[3].iov_len = sizeof(" HTTP/1.1\r\n") - 1; 107221345Sdim 108223017Sdim /* Create a new bucket for this string with a flat string. */ 109223017Sdim new_data = serf_bstrcatv(bucket->allocator, iov, 4, &nbytes); 110223017Sdim new_bucket = serf_bucket_simple_own_create(new_data, nbytes, 111221345Sdim bucket->allocator); 112221345Sdim 113218893Sdim /* Build up the new bucket structure. 114212793Sdim * 115212793Sdim * Note that self needs to become an aggregate bucket so that a 116218893Sdim * pointer to self still represents the "right" data. 117221345Sdim */ 118218893Sdim serf_bucket_aggregate_become(bucket); 119212793Sdim 120218893Sdim /* Insert the two buckets. */ 121212793Sdim serf_bucket_aggregate_append(bucket, new_bucket); 122212793Sdim serf_bucket_aggregate_append(bucket, ctx->headers); 123218893Sdim 124212793Sdim /* If we know the length, then use C-L and the raw body. Otherwise, 125212793Sdim use chunked encoding for the request. */ 126212793Sdim if (ctx->len != LENGTH_UNKNOWN) { 127223017Sdim char buf[30]; 128223017Sdim sprintf(buf, "%" APR_INT64_T_FMT, ctx->len); 129223017Sdim serf_bucket_headers_set(ctx->headers, "Content-Length", buf); 130223017Sdim if (ctx->body != NULL) 131223017Sdim serf_bucket_aggregate_append(bucket, ctx->body); 132212793Sdim } 133212793Sdim else if (ctx->body != NULL) { 134212793Sdim /* Morph the body bucket to a chunked encoding bucket for now. */ 135212793Sdim serf_bucket_headers_setn(ctx->headers, "Transfer-Encoding", "chunked"); 136218893Sdim ctx->body = serf_bucket_chunk_create(ctx->body, bucket->allocator); 137218893Sdim serf_bucket_aggregate_append(bucket, ctx->body); 138212793Sdim } 139234353Sdim 140221345Sdim /* Our private context is no longer needed, and is not referred to by 141221345Sdim * any existing bucket. Toss it. 142221345Sdim */ 143221345Sdim serf_bucket_mem_free(bucket->allocator, ctx); 144221345Sdim} 145221345Sdim 146221345Sdimstatic apr_status_t serf_request_read(serf_bucket_t *bucket, 147218893Sdim apr_size_t requested, 148212793Sdim const char **data, apr_size_t *len) 149234353Sdim{ 150234353Sdim /* Seralize our private data into a new aggregate bucket. */ 151234353Sdim serialize_data(bucket); 152219077Sdim 153219077Sdim /* Delegate to the "new" aggregate bucket to do the read. */ 154219077Sdim return serf_bucket_read(bucket, requested, data, len); 155219077Sdim} 156219077Sdim 157219077Sdimstatic apr_status_t serf_request_readline(serf_bucket_t *bucket, 158219077Sdim int acceptable, int *found, 159234353Sdim const char **data, apr_size_t *len) 160234353Sdim{ 161234353Sdim /* Seralize our private data into a new aggregate bucket. */ 162234353Sdim serialize_data(bucket); 163221345Sdim 164221345Sdim /* Delegate to the "new" aggregate bucket to do the readline. */ 165223017Sdim return serf_bucket_readline(bucket, acceptable, found, data, len); 166221345Sdim} 167221345Sdim 168221345Sdimstatic apr_status_t serf_request_read_iovec(serf_bucket_t *bucket, 169221345Sdim apr_size_t requested, 170221345Sdim int vecs_size, 171221345Sdim struct iovec *vecs, 172221345Sdim int *vecs_used) 173221345Sdim{ 174221345Sdim /* Seralize our private data into a new aggregate bucket. */ 175221345Sdim serialize_data(bucket); 176223017Sdim 177223017Sdim /* Delegate to the "new" aggregate bucket to do the read. */ 178223017Sdim return serf_bucket_read_iovec(bucket, requested, 179223017Sdim vecs_size, vecs, vecs_used); 180223017Sdim} 181223017Sdim 182223017Sdimstatic apr_status_t serf_request_peek(serf_bucket_t *bucket, 183223017Sdim const char **data, 184221345Sdim apr_size_t *len) 185221345Sdim{ 186218893Sdim /* Seralize our private data into a new aggregate bucket. */ 187212793Sdim serialize_data(bucket); 188226633Sdim 189226633Sdim /* Delegate to the "new" aggregate bucket to do the peek. */ 190226633Sdim return serf_bucket_peek(bucket, data, len); 191226633Sdim} 192226633Sdim 193226633Sdimvoid serf_bucket_request_become( 194226633Sdim serf_bucket_t *bucket, 195226633Sdim const char *method, 196226633Sdim const char *uri, 197212793Sdim serf_bucket_t *body) 198212793Sdim{ 199212793Sdim request_context_t *ctx; 200212793Sdim 201212793Sdim ctx = serf_bucket_mem_alloc(bucket->allocator, sizeof(*ctx)); 202212793Sdim ctx->method = method; 203212793Sdim ctx->uri = uri; 204212793Sdim ctx->headers = serf_bucket_headers_create(bucket->allocator); 205212793Sdim ctx->body = body; 206212793Sdim 207212793Sdim bucket->type = &serf_bucket_type_request; 208212793Sdim bucket->data = ctx; 209218893Sdim 210212793Sdim /* The allocator remains the same. */ 211212793Sdim} 212218893Sdim 213218893Sdimconst serf_bucket_type_t serf_bucket_type_request = { 214218893Sdim "REQUEST", 215218893Sdim serf_request_read, 216218893Sdim serf_request_readline, 217218893Sdim serf_request_read_iovec, 218218893Sdim serf_default_read_for_sendfile, 219263508Sdim serf_default_read_bucket, 220212793Sdim serf_request_peek, 221226633Sdim serf_default_destroy_and_data, 222226633Sdim}; 223226633Sdim 224226633Sdim