Beispiel #1
0
static
void completed(enum iostream_proxy_side side ATTR_UNUSED, bool success ATTR_UNUSED, int *u0)
{
	i_assert(*u0 > 0);
	if (--*u0 == 0)
		io_loop_stop(current_ioloop);
}
Beispiel #2
0
static void dsync_connected_callback(int exit_code, const char *error,
				     void *context)
{
	struct dsync_cmd_context *ctx = context;

	ctx->ctx.exit_code = exit_code;
	switch (exit_code) {
	case 0:
		server_connection_extract(ctx->tcp_conn, &ctx->input,
					  &ctx->output, &ctx->ssl_iostream);
		break;
	case SERVER_EXIT_CODE_DISCONNECTED:
		ctx->error = p_strdup_printf(ctx->ctx.pool,
			"Disconnected from remote: %s", error);
		break;
	case EX_NOUSER:
		ctx->error = "Unknown user in remote";
		break;
	default:
		ctx->error = p_strdup_printf(ctx->ctx.pool,
			"Failed to start dsync-server command: %u", exit_code);
		break;
	}
	io_loop_stop(current_ioloop);
}
Beispiel #3
0
static bool
http_client_request_send_error(struct http_client_request *req,
			       unsigned int status, const char *error)
{
	http_client_request_callback_t *callback;
	bool sending = (req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT);
	unsigned int orig_attempts = req->attempts;

	req->state = HTTP_REQUEST_STATE_ABORTED;

	callback = req->callback;
	req->callback = NULL;
	if (callback != NULL) {
		struct http_response response;

		http_response_init(&response, status, error);
		(void)callback(&response, req->context);

		if (req->attempts != orig_attempts) {
			/* retrying */
			req->callback = callback;
			http_client_request_resubmit(req);
			return FALSE;
		} else {
			/* release payload early (prevents server/client deadlock in proxy) */
			if (!sending && req->payload_input != NULL)
				i_stream_unref(&req->payload_input);
		}
	}
	if (req->payload_wait && req->client->ioloop != NULL)
		io_loop_stop(req->client->ioloop);
	return TRUE;
}
Beispiel #4
0
static void pop3c_client_disconnect(struct pop3c_client *client)
{
	client->state = POP3C_CLIENT_STATE_DISCONNECTED;
	client->async_commands = 0;

	if (client->running)
		io_loop_stop(current_ioloop);

	if (client->dns_lookup != NULL)
		dns_lookup_abort(&client->dns_lookup);
	if (client->to != NULL)
		timeout_remove(&client->to);
	if (client->io != NULL)
		io_remove(&client->io);
	if (client->input != NULL)
		i_stream_destroy(&client->input);
	if (client->output != NULL)
		o_stream_destroy(&client->output);
	if (client->ssl_iostream != NULL)
		ssl_iostream_unref(&client->ssl_iostream);
	if (client->fd != -1) {
		if (close(client->fd) < 0)
			i_error("close(pop3c) failed: %m");
		client->fd = -1;
	}
	client_login_callback(client, POP3C_COMMAND_STATE_DISCONNECTED,
			      "Disconnected");
}
Beispiel #5
0
static void sig_die(const siginfo_t *si, void *context)
{
	struct master_service *service = context;

	/* SIGINT comes either from master process or from keyboard. we don't
	   want to log it in either case.*/
	if (si->si_signo != SIGINT) {
		i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
			  si->si_signo, dec2str(si->si_pid),
			  dec2str(si->si_uid),
			  lib_signal_code_to_str(si->si_signo, si->si_code));
	} else if ((service->flags & MASTER_SERVICE_FLAG_NO_IDLE_DIE) != 0) {
		/* never die when idling */
		return;
	} else if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
		/* SIGINT came from master. die only if we're not handling
		   any clients currently. */
		if (service->master_status.available_count !=
		    service->total_available_count)
			return;

		if (service->idle_die_callback != NULL &&
		    !service->idle_die_callback()) {
			/* we don't want to die - send a notification to master
			   so it doesn't think we're ignoring it completely. */
			master_status_send(service, FALSE);
			return;
		}
	}

	service->killed = TRUE;
	io_loop_stop(service->ioloop);
}
Beispiel #6
0
static void test_ostream_multiplex_stream_read(struct istream *is)
{
	uint8_t cid;
	const unsigned char *data;
	size_t siz,dlen=0,pos=0;

	if (i_stream_read_more(is, &data, &siz)>0) {
		/* parse stream */
		for(;pos<siz;) {
			if (dlen > 0) {
				if (dlen < N_ELEMENTS(msgs)) {
					test_assert_idx(memcmp(&data[pos],
							       msgs[dlen], dlen)==0,
							channel_counter[data[0] % 2]);
				}
				channel_counter[data[0] % 2]++;
				pos += dlen;
				dlen = 0;
			} else if (dlen == 0) {
				cid = data[pos] % 2;
				test_assert_idx(data[pos] < 2, channel_counter[cid]);
				pos++;
				dlen = be32_to_cpu_unaligned(&data[pos]);
				pos += 4;
				test_assert(dlen > 0 && dlen < N_ELEMENTS(msgs));
			}
		}
		i_stream_skip(is, siz);
	}

	if (channel_counter[0] > 100 && channel_counter[1] > 100)
		io_loop_stop(current_ioloop);
}
Beispiel #7
0
static void cmd_proxy_list_callback(enum ipc_client_cmd_state state,
				    const char *data, void *context)
{
	bool *seen_header = context;

	switch (state) {
	case IPC_CLIENT_CMD_STATE_REPLY: {
		const char *const *args = t_strsplit_tabescaped(data);

		if (!*seen_header) {
			cmd_proxy_list_header(args);
			*seen_header = TRUE;
		} else {
			for (; *args != NULL; args++)
				doveadm_print(*args);
		}
		return;
	}
	case IPC_CLIENT_CMD_STATE_OK:
		break;
	case IPC_CLIENT_CMD_STATE_ERROR:
		i_error("LIST-FULL failed: %s", data);
		break;
	}
	io_loop_stop(current_ioloop);
}
Beispiel #8
0
static void pop3c_client_input_reply(struct pop3c_client *client)
{
	i_assert(client->state == POP3C_CLIENT_STATE_DONE);

	if (client->to != NULL)
		timeout_reset(client->to);
	client->input_line = i_stream_read_next_line(client->input);
	if (client->input_line != NULL)
		io_loop_stop(current_ioloop);
	else if (client->input->closed || client->input->eof ||
		 client->input->stream_errno != 0) {
		/* disconnected */
		i_error("pop3c(%s): Server disconnected unexpectedly",
			client->set.host);
		pop3c_client_disconnect(client);
		io_loop_stop(current_ioloop);
	}
}
Beispiel #9
0
static void pop3c_client_login_finished(struct pop3c_client *client)
{
	io_remove(&client->io);
	timeout_remove(&client->to);
	client->state = POP3C_CLIENT_STATE_DONE;

	if (client->running)
		io_loop_stop(current_ioloop);
}
Beispiel #10
0
static void memcached_conn_destroy(struct connection *_conn)
{
	struct memcached_connection *conn = (struct memcached_connection *)_conn;

	conn->dict->connected = FALSE;
	connection_disconnect(_conn);

	if (conn->dict->ioloop != NULL)
		io_loop_stop(conn->dict->ioloop);
}
Beispiel #11
0
static void
fts_tika_parser_response(const struct http_response *response,
			 struct tika_fts_parser *parser)
{
	i_assert(parser->payload == NULL);

	switch (response->status) {
	case 200:
		/* read response */
		if (response->payload == NULL)
			parser->payload = i_stream_create_from_data("", 0);
		else {
			i_stream_ref(response->payload);
			parser->payload = response->payload;
		}
		break;
	case 204: /* empty response */
	case 415: /* Unsupported Media Type */
	case 422: /* Unprocessable Entity */
		if (parser->user->mail_debug) {
			i_debug("fts_tika: PUT %s failed: %u %s",
				mail_user_plugin_getenv(parser->user, "fts_tika"),
				response->status, response->reason);
		}
		parser->payload = i_stream_create_from_data("", 0);
		break;
	case 500:
		/* Server Error - the problem could be anything (in Tika or
		   HTTP server or proxy) and might be retriable, but Tika has
		   trouble processing some documents and throws up this error
		   every time for those documents.

		   Unfortunately we can't easily re-send the request here,
		   because we would have to re-send the entire payload, which
		   isn't available anymore here. So we'd need to indicate
		   in fts_parser_deinit() that we want to retry.
		   FIXME: do this in v2.3. For now we'll just ignore it. */
		i_info("fts_tika: PUT %s failed: %u %s - ignoring",
		       mail_user_plugin_getenv(parser->user, "fts_tika"),
		       response->status, response->reason);
		parser->payload = i_stream_create_from_data("", 0);
		break;

	default:
		i_error("fts_tika: PUT %s failed: %u %s",
			mail_user_plugin_getenv(parser->user, "fts_tika"),
			response->status, response->reason);
		parser->failed = TRUE;
		break;
	}
	parser->http_req = NULL;
	io_loop_stop(current_ioloop);
}
Beispiel #12
0
static void
http_server_istream_read_any(struct http_server_istream *hsristream)
{
	struct istream_private *stream = &hsristream->istream;
	struct http_server *server = hsristream->req->server;
	ssize_t ret;

	if ((ret=i_stream_read_copy_from_parent
		(&stream->istream)) > 0) {
		hsristream->read_status = ret;
		io_loop_stop(server->ioloop);
	}
}
Beispiel #13
0
static void
fts_tika_parser_response(const struct http_response *response,
                         struct tika_fts_parser *parser)
{
    i_assert(parser->payload == NULL);

    switch (response->status) {
    case 200:
        /* read response */
        if (response->payload == NULL)
            parser->payload = i_stream_create_from_data("", 0);
        else {
            i_stream_ref(response->payload);
            parser->payload = response->payload;
        }
        break;
    case 204: /* empty response */
    case 415: /* Unsupported Media Type */
    case 422: /* Unprocessable Entity */
        if (parser->user->mail_debug) {
            i_debug("fts_tika: PUT %s failed: %u %s",
                    mail_user_plugin_getenv(parser->user, "fts_tika"),
                    response->status, response->reason);
        }
        parser->payload = i_stream_create_from_data("", 0);
        break;
    case 500:
        /* Server Error - the problem could be anything (in Tika or
           HTTP server or proxy) and might be retriable, but Tika has
           trouble processing some documents and throws up this error
           every time for those documents. So we try retrying this a
           couple of times, but if that doesn't work we'll just ignore
           it. */
        if (http_client_request_try_retry(parser->http_req))
            return;
        i_info("fts_tika: PUT %s failed: %u %s - ignoring",
               mail_user_plugin_getenv(parser->user, "fts_tika"),
               response->status, response->reason);
        parser->payload = i_stream_create_from_data("", 0);
        break;

    default:
        i_error("fts_tika: PUT %s failed: %u %s",
                mail_user_plugin_getenv(parser->user, "fts_tika"),
                response->status, response->reason);
        parser->failed = TRUE;
        break;
    }
    parser->http_req = NULL;
    io_loop_stop(current_ioloop);
}
Beispiel #14
0
static int memcached_input_get(struct memcached_connection *conn)
{
	const unsigned char *data;
	size_t size;
	uint32_t body_len, value_pos;
	uint16_t key_len, key_pos, status;
	uint8_t extras_len, data_type;

	data = i_stream_get_data(conn->conn.input, &size);
	if (size < MEMCACHED_REPLY_HDR_LENGTH)
		return 0;

	if (data[0] != MEMCACHED_REPLY_HDR_MAGIC) {
		i_error("memcached: Invalid reply magic: %u != %u",
			data[0], MEMCACHED_REPLY_HDR_MAGIC);
		return -1;
	}
	memcpy(&body_len, data+8, 4); body_len = ntohl(body_len);
	body_len += MEMCACHED_REPLY_HDR_LENGTH;
	if (size < body_len) {
		/* we haven't read the whole response yet */
		return 0;
	}

	memcpy(&key_len, data+2, 2); key_len = ntohs(key_len);
	extras_len = data[4];
	data_type = data[5];
	memcpy(&status, data+6, 2); status = ntohs(status);
	if (data_type != MEMCACHED_DATA_TYPE_RAW) {
		i_error("memcached: Unsupported data type: %u != %u",
			data[0], MEMCACHED_DATA_TYPE_RAW);
		return -1;
	}

	key_pos = MEMCACHED_REPLY_HDR_LENGTH + extras_len;
	value_pos = key_pos + key_len;
	if (value_pos > body_len) {
		i_error("memcached: Invalid key/extras lengths");
		return -1;
	}
	conn->reply.value = data + value_pos;
	conn->reply.value_len = body_len - value_pos;
	conn->reply.status = status;

	i_stream_skip(conn->conn.input, body_len);
	conn->reply.reply_received = TRUE;

	if (conn->dict->ioloop != NULL)
		io_loop_stop(conn->dict->ioloop);
	return 1;
}
Beispiel #15
0
static void memcached_conn_connected(struct connection *_conn, bool success)
{
	struct memcached_connection *conn =
		(struct memcached_connection *)_conn;

	if (!success) {
		i_error("memcached: connect(%s, %u) failed: %m",
			net_ip2addr(&conn->dict->ip), conn->dict->port);
	} else {
		conn->dict->connected = TRUE;
	}
	if (conn->dict->ioloop != NULL)
		io_loop_stop(conn->dict->ioloop);
}
Beispiel #16
0
static void
http_client_request_remove(struct http_client_request *req)
{
	struct http_client *client = req->client;

	if (req->listed) {
		/* only decrease pending request counter if this request was submitted */
		DLLIST_REMOVE(&client->requests_list, req);
		client->requests_count--;
	}
	req->listed = FALSE;

	if (client->requests_count == 0 && client->ioloop != NULL)
		io_loop_stop(client->ioloop);
}
Beispiel #17
0
void http_client_request_finish(struct http_client_request **_req)
{
	struct http_client_request *req = *_req;

	if (req->state >= HTTP_REQUEST_STATE_FINISHED)
		return;

	http_client_request_debug(req, "Finished");

	req->callback = NULL;
	req->state = HTTP_REQUEST_STATE_FINISHED;

	if (req->payload_wait && req->client->ioloop != NULL)
		io_loop_stop(req->client->ioloop);
	http_client_request_unref(_req);
}
Beispiel #18
0
void http_client_request_finish(struct http_client_request *req)
{
	if (req->state >= HTTP_REQUEST_STATE_FINISHED)
		return;

	i_assert(req->refcount > 0);

	http_client_request_debug(req, "Finished");

	req->callback = NULL;
	req->state = HTTP_REQUEST_STATE_FINISHED;

	if (req->queue != NULL)
		http_client_queue_drop_request(req->queue, req);
	if (req->payload_wait && req->client->ioloop != NULL)
		io_loop_stop(req->client->ioloop);
	http_client_request_unref(&req);
}
Beispiel #19
0
static void program_client_disconnect
(struct program_client *pclient, bool force)
{
	int ret, error = FALSE;

	if ( pclient->ioloop != NULL )
		io_loop_stop(pclient->ioloop);

	if ( pclient->disconnected )
		return;

	if ( (ret=program_client_close_output(pclient)) < 0 )
		error = TRUE;

	program_client_disconnect_extra_fds(pclient);
	if ( (ret=pclient->disconnect(pclient, force)) < 0 )
		error = TRUE;

	if ( pclient->program_input != NULL ) {
		if (pclient->output_seekable)
			i_stream_unref(&pclient->program_input);
		else
			i_stream_destroy(&pclient->program_input);
	} 
	if ( pclient->program_output != NULL )
		o_stream_destroy(&pclient->program_output);

	if ( pclient->to != NULL )
		timeout_remove(&pclient->to);
	if ( pclient->io != NULL )
		io_remove(&pclient->io);

	if (pclient->fd_in != -1 && close(pclient->fd_in) < 0)
		i_error("close(%s) failed: %m", pclient->path);
	if (pclient->fd_out != -1 && pclient->fd_out != pclient->fd_in
		&& close(pclient->fd_out) < 0)
		i_error("close(%s/out) failed: %m", pclient->path);
	pclient->fd_in = pclient->fd_out = -1;
	
	pclient->disconnected = TRUE;
	if (error && pclient->error == PROGRAM_CLIENT_ERROR_NONE ) {
		pclient->error = PROGRAM_CLIENT_ERROR_UNKNOWN;
	}
}
Beispiel #20
0
bool http_client_request_unref(struct http_client_request **_req)
{
	struct http_client_request *req = *_req;
	struct http_client *client = req->client;

	i_assert(req->refcount > 0);

	*_req = NULL;

	if (--req->refcount > 0)
		return TRUE;

	http_client_request_debug(req, "Free (requests left=%d)",
		client->requests_count);

	/* cannot be destroyed while it is still pending */
	i_assert(req->conn == NULL);

	if (req->queue != NULL)
		http_client_queue_drop_request(req->queue, req);

	if (req->destroy_callback != NULL) {
		req->destroy_callback(req->destroy_context);
		req->destroy_callback = NULL;
	}

	http_client_request_remove(req);

	if (client->requests_count == 0 && client->ioloop != NULL)
		io_loop_stop(client->ioloop);

	if (req->delayed_error != NULL)
		http_client_remove_request_error(req->client, req);
	if (req->payload_input != NULL)
		i_stream_unref(&req->payload_input);
	if (req->payload_output != NULL)
		o_stream_unref(&req->payload_output);
	if (req->headers != NULL)
		str_free(&req->headers);
	pool_unref(&req->pool);
	return FALSE;
}
Beispiel #21
0
static void pop3c_client_dot_input(struct pop3c_client *client)
{
	ssize_t ret;

	if (client->to != NULL)
		timeout_reset(client->to);
	while ((ret = i_stream_read(client->dot_input)) > 0 || ret == -2) {
		i_stream_skip(client->dot_input,
			      i_stream_get_data_size(client->dot_input));
	}
	if (ret != 0) {
		i_assert(ret == -1);
		if (client->dot_input->stream_errno != 0) {
			i_error("pop3c(%s): Server disconnected unexpectedly",
				client->set.host);
			pop3c_client_disconnect(client);
		}
		if (client->running)
			io_loop_stop(current_ioloop);
	}
}
static void script_client_disconnect
(struct script_client *sclient, bool force)
{
	int ret, error = FALSE;

	if ( sclient->ioloop != NULL )
		io_loop_stop(sclient->ioloop);

	if ( sclient->disconnected )
		return;

	if ( (ret=sclient->close_output(sclient)) < 0 )
		error = TRUE;
	
	if ( (ret=sclient->disconnect(sclient, force)) < 0 )
		error = TRUE;

	if ( sclient->script_input != NULL )
		i_stream_destroy(&sclient->script_input);
	if ( sclient->script_output != NULL )
		o_stream_destroy(&sclient->script_output);

	if ( sclient->to != NULL )
		timeout_remove(&sclient->to);
	if ( sclient->io != NULL )
		io_remove(&sclient->io);

	if (sclient->fd_in != -1 && close(sclient->fd_in) < 0)
		i_error("close(%s) failed: %m", sclient->path);
	if (sclient->fd_out != -1 && sclient->fd_out != sclient->fd_out)
		i_error("close(%s/out) failed: %m", sclient->path);
	sclient->fd_in = sclient->fd_out = -1;
	
	sclient->disconnected = TRUE;
	if (error && sclient->error == SCRIPT_CLIENT_ERROR_NONE ) {
		sclient->error = SCRIPT_CLIENT_ERROR_UNKNOWN;
	}
}
Beispiel #23
0
static void rawlog_proxy_destroy(struct rawlog_proxy *proxy)
{
	if (proxy->in_output != NULL) {
		o_stream_uncork(proxy->in_output);
		if (o_stream_nfinish(proxy->in_output) < 0) {
			i_error("write(in) failed: %s",
				o_stream_get_error(proxy->in_output));
		}
		o_stream_destroy(&proxy->in_output);
	}
	if (proxy->out_output != NULL) {
		o_stream_uncork(proxy->out_output);
		if (o_stream_nfinish(proxy->out_output) < 0) {
			i_error("write(out) failed: %s",
				o_stream_get_error(proxy->out_output));
		}
		o_stream_destroy(&proxy->out_output);
	}
	if (proxy->client_io != NULL)
		io_remove(&proxy->client_io);
	if (proxy->server_io != NULL)
		io_remove(&proxy->server_io);
	if (proxy->to_flush != NULL)
		timeout_remove(&proxy->to_flush);

	o_stream_destroy(&proxy->client_output);
	o_stream_destroy(&proxy->server_output);

	if (close(proxy->client_in_fd) < 0)
		i_error("close(client_in_fd) failed: %m");
	if (close(proxy->client_out_fd) < 0)
		i_error("close(client_out_fd) failed: %m");
	if (close(proxy->server_fd) < 0)
		i_error("close(server_fd) failed: %m");
	i_free(proxy);

	io_loop_stop(ioloop);
}
Beispiel #24
0
void http_client_request_abort(struct http_client_request **_req)
{
	struct http_client_request *req = *_req;
	bool sending = (req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT);

	*_req = NULL;

	if (req->state >= HTTP_REQUEST_STATE_FINISHED)
		return;

	req->callback = NULL;
	req->state = HTTP_REQUEST_STATE_ABORTED;

	/* release payload early (prevents server/client deadlock in proxy) */
	if (!sending && req->payload_input != NULL)
		i_stream_unref(&req->payload_input);

	if (req->queue != NULL)
		http_client_queue_drop_request(req->queue, req);
	if (req->payload_wait && req->client->ioloop != NULL)
		io_loop_stop(req->client->ioloop);
	http_client_request_destroy(&req);
}
Beispiel #25
0
static void
fts_tika_parser_response(const struct http_response *response,
			 struct tika_fts_parser *parser)
{
	i_assert(parser->payload == NULL);

	switch (response->status) {
	case 200:
		/* read response */
		if (response->payload == NULL)
			parser->payload = i_stream_create_from_data("", 0);
		else {
			i_stream_ref(response->payload);
			parser->payload = response->payload;
		}
		break;
	case 204: /* empty response */
	case 415: /* Unsupported Media Type */
	case 422: /* Unprocessable Entity */
		if (parser->user->mail_debug) {
			i_debug("fts_tika: PUT %s failed: %u %s",
				mail_user_plugin_getenv(parser->user, "fts_tika"),
				response->status, response->reason);
		}
		parser->payload = i_stream_create_from_data("", 0);
		break;
	default:
		i_error("fts_tika: PUT %s failed: %u %s",
			mail_user_plugin_getenv(parser->user, "fts_tika"),
			response->status, response->reason);
		parser->failed = TRUE;
		break;
	}
	parser->http_req = NULL;
	io_loop_stop(current_ioloop);
}
Beispiel #26
0
void http_server_request_destroy(struct http_server_request **_req)
{
	struct http_server_request *req = *_req;
	struct http_server *server = req->server;

	http_server_request_debug(req, "Destroy");

	/* just make sure the request ends in a proper state */
	if (req->state < HTTP_SERVER_REQUEST_STATE_FINISHED)
		req->state = HTTP_SERVER_REQUEST_STATE_ABORTED;

	if (server->ioloop != NULL)
		io_loop_stop(server->ioloop);

	if (req->delay_destroy) {
		req->destroy_pending = TRUE;
	} else if (req->destroy_callback != NULL) {
		void (*callback)(void *) = req->destroy_callback;

		req->destroy_callback = NULL;
		callback(req->destroy_context);
	}
	http_server_request_unref(_req);
}
Beispiel #27
0
void http_client_request_unref(struct http_client_request **_req)
{
	struct http_client_request *req = *_req;
	struct http_client *client = req->client;

	i_assert(req->refcount > 0);

	if (--req->refcount > 0)
		return;

	if (req->destroy_callback != NULL) {
		req->destroy_callback(req->destroy_context);
		req->destroy_callback = NULL;
	}

	/* only decrease pending request counter if this request was submitted */
	if (req->state > HTTP_REQUEST_STATE_NEW)
		req->client->pending_requests--;

	http_client_request_debug(req, "Destroy (requests left=%d)",
		client->pending_requests);

	if (client->pending_requests == 0 && client->ioloop != NULL)
		io_loop_stop(client->ioloop);

	if (req->delayed_error != NULL)
		http_client_host_remove_request_error(req->host, req);
	if (req->payload_input != NULL)
		i_stream_unref(&req->payload_input);
	if (req->payload_output != NULL)
		o_stream_unref(&req->payload_output);
	if (req->headers != NULL)
		str_free(&req->headers);
	pool_unref(&req->pool);
	*_req = NULL;
}
Beispiel #28
0
int http_client_request_send_more(struct http_client_request *req,
				  const char **error_r)
{
	struct http_client_connection *conn = req->conn;
	struct ostream *output = req->payload_output;
	off_t ret;
	int fd;

	i_assert(req->payload_input != NULL);
	i_assert(req->payload_output != NULL);

	if (conn->io_req_payload != NULL)
		io_remove(&conn->io_req_payload);

	/* chunked ostream needs to write to the parent stream's buffer */
	o_stream_set_max_buffer_size(output, IO_BLOCK_SIZE);
	ret = o_stream_send_istream(output, req->payload_input);
	o_stream_set_max_buffer_size(output, (size_t)-1);

	if (req->payload_input->stream_errno != 0) {
		/* the payload stream assigned to this request is broken,
		   fail this the request immediately */
		http_client_request_send_error(req,
			HTTP_CLIENT_REQUEST_ERROR_BROKEN_PAYLOAD,
			"Broken payload stream");

		/* we're in the middle of sending a request, so the connection
		   will also have to be aborted */
		errno = req->payload_input->stream_errno;
		*error_r = t_strdup_printf("read(%s) failed: %s",
					   i_stream_get_name(req->payload_input),
					   i_stream_get_error(req->payload_input));
		ret = -1;
	} else if (output->stream_errno != 0) {
		/* failed to send request */
		errno = output->stream_errno;
		*error_r = t_strdup_printf("write(%s) failed: %s",
					   o_stream_get_name(output),
					   o_stream_get_error(output));
		ret = -1;
	} else {
		i_assert(ret >= 0);
	}

	if (ret < 0 || i_stream_is_eof(req->payload_input)) {
		if (!req->payload_chunked &&
			req->payload_input->v_offset - req->payload_offset != req->payload_size) {
			*error_r = "stream input size changed [BUG]";
			i_error("stream input size changed"); //FIXME
			return -1;
		}

		if (req->payload_wait) {
			conn->output_locked = TRUE;
			if (req->client->ioloop != NULL)
				io_loop_stop(req->client->ioloop);
		} else {
			http_client_request_finish_payload_out(req);
		}
	} else if (i_stream_get_data_size(req->payload_input) > 0) {
		/* output is blocking */
		conn->output_locked = TRUE;
		o_stream_set_flush_pending(output, TRUE);
		http_client_request_debug(req, "Partially sent payload");
	} else {
		/* input is blocking */
		fd = i_stream_get_fd(req->payload_input);
		conn->output_locked = TRUE;	
		i_assert(fd >= 0);
		conn->io_req_payload = io_add
			(fd, IO_READ, http_client_request_payload_input, req);
	}
	return ret < 0 ? -1 : 0;
}
Beispiel #29
0
int http_client_request_send_more(struct http_client_request *req,
				  bool pipelined, const char **error_r)
{
	struct http_client_connection *conn = req->conn;
	struct ostream *output = req->payload_output;
	enum ostream_send_istream_result res;

	i_assert(req->payload_input != NULL);
	i_assert(req->payload_output != NULL);

	if (conn->io_req_payload != NULL)
		io_remove(&conn->io_req_payload);

	/* chunked ostream needs to write to the parent stream's buffer */
	o_stream_set_max_buffer_size(output, IO_BLOCK_SIZE);
	res = o_stream_send_istream(output, req->payload_input);
	o_stream_set_max_buffer_size(output, (size_t)-1);

	switch (res) {
	case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
		/* finished sending */
		if (!req->payload_chunked &&
		    req->payload_input->v_offset - req->payload_offset != req->payload_size) {
			*error_r = t_strdup_printf("BUG: stream '%s' input size changed: "
				"%"PRIuUOFF_T"-%"PRIuUOFF_T" != %"PRIuUOFF_T,
				i_stream_get_name(req->payload_input),
				req->payload_input->v_offset, req->payload_offset, req->payload_size);
			i_error("%s", *error_r); //FIXME: remove?
			return -1;
		}

		if (req->payload_wait) {
			/* this chunk of input is finished
			   (client needs to act; disable timeout) */
			i_assert(!pipelined);
			conn->output_locked = TRUE;
			http_client_connection_stop_request_timeout(conn);
			if (req->client->ioloop != NULL)
				io_loop_stop(req->client->ioloop);
		} else {
			/* finished sending payload */
			http_client_request_finish_payload_out(req);
		}
		return 0;
	case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
		/* input is blocking (client needs to act; disable timeout) */
		conn->output_locked = TRUE;	
		if (!pipelined)
			http_client_connection_stop_request_timeout(conn);
		conn->io_req_payload = io_add_istream(req->payload_input,
			http_client_request_payload_input, req);
		return 0;
	case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
		/* output is blocking (server needs to act; enable timeout) */
		conn->output_locked = TRUE;
		if (!pipelined)
			http_client_connection_start_request_timeout(conn);
		http_client_request_debug(req, "Partially sent payload");
		return 0;
	case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
		/* we're in the middle of sending a request, so the connection
		   will also have to be aborted */
		*error_r = t_strdup_printf("read(%s) failed: %s",
					   i_stream_get_name(req->payload_input),
					   i_stream_get_error(req->payload_input));

		/* the payload stream assigned to this request is broken,
		   fail this the request immediately */
		http_client_request_error(&req,
			HTTP_CLIENT_REQUEST_ERROR_BROKEN_PAYLOAD,
			"Broken payload stream");
		return -1;
	case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
		/* failed to send request */
		*error_r = t_strdup_printf("write(%s) failed: %s",
					   o_stream_get_name(output),
					   o_stream_get_error(output));
		return -1;
	}
	i_unreached();
}