<commit_before>/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "net.h"
#include "str.h"
#include "hash.h"
#include "array.h"
#include "istream.h"
#include "ostream.h"
#include "http-url.h"
#include "http-response-parser.h"

#include "http-client-private.h"

/*
 * Logging
 */

static inline void
http_client_request_debug(struct http_client_request *req,
	const char *format, ...) ATTR_FORMAT(2, 3);

static inline void
http_client_request_debug(struct http_client_request *req,
	const char *format, ...)
{
	va_list args;

	if (req->client->set.debug) {
		va_start(args, format);	
		i_debug("http-client: request %s: %s",
			http_client_request_label(req), t_strdup_vprintf(format, args));
		va_end(args);
	}
}

/*
 * Request
 */

#undef http_client_request
struct http_client_request *
http_client_request(struct http_client *client,
		    const char *method, const char *host, const char *target,
		    http_client_request_callback_t *callback, void *context)
{
	pool_t pool;
	struct http_client_request *req;

	pool = pool_alloconly_create("http client request", 2048);
	req = p_new(pool, struct http_client_request, 1);
	req->pool = pool;
	req->refcount = 1;
	req->client = client;
	req->method = p_strdup(pool, method);
	req->hostname = p_strdup(pool, host);
	req->port = HTTP_DEFAULT_PORT;
	req->target = p_strdup(pool, target);
	req->callback = callback;
	req->context = context;
	req->headers = str_new(default_pool, 256);

	req->state = HTTP_REQUEST_STATE_NEW;
	return req;
}

void http_client_request_ref(struct http_client_request *req)
{
	req->refcount++;
}

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;

	/* 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 (req->input != NULL)
		i_stream_unref(&req->input);
	str_free(&req->headers);
	pool_unref(&req->pool);
	*_req = NULL;
}

void http_client_request_set_port(struct http_client_request *req,
	unsigned int port)
{
	i_assert(req->state == HTTP_REQUEST_STATE_NEW);
	req->port = port;
}

void http_client_request_set_ssl(struct http_client_request *req,
	bool ssl)
{
	i_assert(req->state == HTTP_REQUEST_STATE_NEW);
	if (ssl) {
		if (!req->ssl && req->port == HTTP_DEFAULT_PORT)
			req->port = HTTPS_DEFAULT_PORT;
	} else {
		if (req->ssl && req->port == HTTPS_DEFAULT_PORT)
			req->port = HTTP_DEFAULT_PORT;
	}
	req->ssl = ssl;
}

void http_client_request_set_urgent(struct http_client_request *req)
{
	i_assert(req->state == HTTP_REQUEST_STATE_NEW);
	req->urgent = TRUE;
}

void http_client_request_add_header(struct http_client_request *req,
				    const char *key, const char *value)
{
	i_assert(req->state == HTTP_REQUEST_STATE_NEW);
	str_printfa(req->headers, "%s: %s\r\n", key, value);
}

void http_client_request_set_payload(struct http_client_request *req,
				     struct istream *input, bool sync)
{
	i_assert(req->state == HTTP_REQUEST_STATE_NEW);
	i_assert(req->input == NULL);

	i_stream_ref(input);
	req->input = input;
	if (i_stream_get_size(input, TRUE, &req->input_size) <= 0)
		i_unreached(); //FIXME	
	req->input_offset = input->v_offset;

	/* prepare request payload sync using 100 Continue response from server */
	if (req->input_size > 0 && sync) {
		req->payload_sync = TRUE;
	}
}

void http_client_request_submit(struct http_client_request *req)
{
	struct http_client_host *host;

	i_assert(req->state == HTTP_REQUEST_STATE_NEW);
	http_client_request_debug(req, "Submitted");
	
	host = http_client_host_get(req->client, req->hostname);
	http_client_host_submit_request(host, req);
	req->state = HTTP_REQUEST_STATE_QUEUED;
	req->client->pending_requests++;
}

int http_client_request_send_more(struct http_client_request *req)
{
	struct http_client_connection *conn = req->conn;
	struct ostream *output = conn->conn.output;
	int ret = 0;

	i_assert(req->input != NULL);

	o_stream_set_max_buffer_size(output, 0);
	if (o_stream_send_istream(output, req->input) < 0)
		ret = -1;
	o_stream_set_max_buffer_size(output, (size_t)-1);

	if (req->input->eof) {
		if (req->input->v_offset != req->input_size) {
			i_error("stream input size changed"); //FIXME
			return -1;
		}
		req->state = HTTP_REQUEST_STATE_WAITING;
		conn->output_locked = FALSE;
		http_client_request_debug(req, "Sent all payload");

	} else {
		conn->output_locked = TRUE;
		o_stream_set_flush_pending(output, TRUE);
		http_client_request_debug(req, "Partially sent payload");
	}
	return ret;<commit_msg>lib-http: Fixed sending HTTP request's payload.<commit_after>/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "net.h"
#include "str.h"
#include "hash.h"
#include "array.h"
#include "istream.h"
#include "ostream.h"
#include "http-url.h"
#include "http-response-parser.h"

#include "http-client-private.h"

/*
 * Logging
 */

static inline void
http_client_request_debug(struct http_client_request *req,
	const char *format, ...) ATTR_FORMAT(2, 3);

static inline void
http_client_request_debug(struct http_client_request *req,
	const char *format, ...)
{
	va_list args;

	if (req->client->set.debug) {
		va_start(args, format);	
		i_debug("http-client: request %s: %s",
			http_client_request_label(req), t_strdup_vprintf(format, args));
		va_end(args);
	}
}

/*
 * Request
 */

#undef http_client_request
struct http_client_request *
http_client_request(struct http_client *client,
		    const char *method, const char *host, const char *target,
		    http_client_request_callback_t *callback, void *context)
{
	pool_t pool;
	struct http_client_request *req;

	pool = pool_alloconly_create("http client request", 2048);
	req = p_new(pool, struct http_client_request, 1);
	req->pool = pool;
	req->refcount = 1;
	req->client = client;
	req->method = p_strdup(pool, method);
	req->hostname = p_strdup(pool, host);
	req->port = HTTP_DEFAULT_PORT;
	req->target = p_strdup(pool, target);
	req->callback = callback;
	req->context = context;
	req->headers = str_new(default_pool, 256);

	req->state = HTTP_REQUEST_STATE_NEW;
	return req;
}

void http_client_request_ref(struct http_client_request *req)
{
	req->refcount++;
}

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;

	/* 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 (req->input != NULL)
		i_stream_unref(&req->input);
	str_free(&req->headers);
	pool_unref(&req->pool);
	*_req = NULL;
}

void http_client_request_set_port(struct http_client_request *req,
	unsigned int port)
{
	i_assert(req->state == HTTP_REQUEST_STATE_NEW);
	req->port = port;
}

void http_client_request_set_ssl(struct http_client_request *req,
	bool ssl)
{
	i_assert(req->state == HTTP_REQUEST_STATE_NEW);
	if (ssl) {
		if (!req->ssl && req->port == HTTP_DEFAULT_PORT)
			req->port = HTTPS_DEFAULT_PORT;
	} else {
		if (req->ssl && req->port == HTTPS_DEFAULT_PORT)
			req->port = HTTP_DEFAULT_PORT;
	}
	req->ssl = ssl;
}

void http_client_request_set_urgent(struct http_client_request *req)
{
	i_assert(req->state == HTTP_REQUEST_STATE_NEW);
	req->urgent = TRUE;
}

void http_client_request_add_header(struct http_client_request *req,
				    const char *key, const char *value)
{
	i_assert(req->state == HTTP_REQUEST_STATE_NEW);
	str_printfa(req->headers, "%s: %s\r\n", key, value);
}

void http_client_request_set_payload(struct http_client_request *req,
				     struct istream *input, bool sync)
{
	i_assert(req->state == HTTP_REQUEST_STATE_NEW);
	i_assert(req->input == NULL);

	i_stream_ref(input);
	req->input = input;
	if (i_stream_get_size(input, TRUE, &req->input_size) <= 0)
		i_unreached(); //FIXME	
	req->input_offset = input->v_offset;

	/* prepare request payload sync using 100 Continue response from server */
	if (req->input_size > 0 && sync) {
		req->payload_sync = TRUE;
	}
}

void http_client_request_submit(struct http_client_request *req)
{
	struct http_client_host *host;

	i_assert(req->state == HTTP_REQUEST_STATE_NEW);
	http_client_request_debug(req, "Submitted");
	
	host = http_client_host_get(req->client, req->hostname);
	http_client_host_submit_request(host, req);
	req->state = HTTP_REQUEST_STATE_QUEUED;
	req->client->pending_requests++;
}

int http_client_request_send_more(struct http_client_request *req)
{
	struct http_client_connection *conn = req->conn;
	struct ostream *output = conn->conn.output;
	int ret = 0;

	i_assert(req->input != NULL);

	o_stream_set_max_buffer_size(output, 0);
	if (o_stream_send_istream(output, req->input) < 0)
		ret = -1;
	o_stream_set_max_buffer_size(output, (size_t)-1);

	if (!i_stream_have_bytes_left(req->input)) {
		if (req->input->v_offset != req->input_size) {
			i_error("stream input size changed"); //FIXME
			return -1;
		}
		req->state = HTTP_REQUEST_STATE_WAITING;
		conn->output_locked = FALSE;
		http_client_request_debug(req, "Sent all payload");

	} else {
		conn->output_locked = TRUE;
		o_stream_set_flush_pending(output, TRUE);
		http_client_request_debug(req, "Partially sent payload");
	}
	return ret;
{'fraction_non_alphanumeric': 0.13404742096505823, 'fraction_numerical': 0.005823627287853577, 'mean_word_length': 5.2245954692556635, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 140, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6065649', 'n_tokens_mistral': 3629, 'n_tokens_neox': 3453, 'n_words': 722}