1/* ==================================================================== 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 * ==================================================================== 19 */ 20 21#include <apr_pools.h> 22#include <apr_network_io.h> 23 24#include "serf.h" 25#include "serf_private.h" 26#include "serf_bucket_util.h" 27 28 29typedef struct { 30 apr_socket_t *skt; 31 32 serf_databuf_t databuf; 33 34 /* Progress callback */ 35 serf_progress_t progress_func; 36 void *progress_baton; 37} socket_context_t; 38 39 40static apr_status_t socket_reader(void *baton, apr_size_t bufsize, 41 char *buf, apr_size_t *len) 42{ 43 socket_context_t *ctx = baton; 44 apr_status_t status; 45 46 *len = bufsize; 47 status = apr_socket_recv(ctx->skt, buf, len); 48 49 if (status && !APR_STATUS_IS_EAGAIN(status)) 50 serf__log_skt(SOCK_VERBOSE, __FILE__, ctx->skt, 51 "socket_recv error %d\n", status); 52 53 if (*len) 54 serf__log_skt(SOCK_MSG_VERBOSE, __FILE__, ctx->skt, 55 "--- socket_recv:\n%.*s\n-(%d)-\n", 56 *len, buf, *len); 57 58 if (ctx->progress_func && *len) 59 ctx->progress_func(ctx->progress_baton, *len, 0); 60 61 return status; 62} 63 64serf_bucket_t *serf_bucket_socket_create( 65 apr_socket_t *skt, 66 serf_bucket_alloc_t *allocator) 67{ 68 socket_context_t *ctx; 69 70 /* Oh, well. */ 71 ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx)); 72 ctx->skt = skt; 73 74 serf_databuf_init(&ctx->databuf); 75 ctx->databuf.read = socket_reader; 76 ctx->databuf.read_baton = ctx; 77 78 ctx->progress_func = NULL; 79 ctx->progress_baton = NULL; 80 return serf_bucket_create(&serf_bucket_type_socket, allocator, ctx); 81} 82 83void serf_bucket_socket_set_read_progress_cb( 84 serf_bucket_t *bucket, 85 const serf_progress_t progress_func, 86 void *progress_baton) 87{ 88 socket_context_t *ctx = bucket->data; 89 90 ctx->progress_func = progress_func; 91 ctx->progress_baton = progress_baton; 92} 93 94static apr_status_t serf_socket_read(serf_bucket_t *bucket, 95 apr_size_t requested, 96 const char **data, apr_size_t *len) 97{ 98 socket_context_t *ctx = bucket->data; 99 100 return serf_databuf_read(&ctx->databuf, requested, data, len); 101} 102 103static apr_status_t serf_socket_readline(serf_bucket_t *bucket, 104 int acceptable, int *found, 105 const char **data, apr_size_t *len) 106{ 107 socket_context_t *ctx = bucket->data; 108 109 return serf_databuf_readline(&ctx->databuf, acceptable, found, data, len); 110} 111 112static apr_status_t serf_socket_peek(serf_bucket_t *bucket, 113 const char **data, 114 apr_size_t *len) 115{ 116 socket_context_t *ctx = bucket->data; 117 118 return serf_databuf_peek(&ctx->databuf, data, len); 119} 120 121const serf_bucket_type_t serf_bucket_type_socket = { 122 "SOCKET", 123 serf_socket_read, 124 serf_socket_readline, 125 serf_default_read_iovec, 126 serf_default_read_for_sendfile, 127 serf_default_read_bucket, 128 serf_socket_peek, 129 serf_default_destroy_and_data, 130}; 131