http-provider.c 18.5 KB
Newer Older
Simon Morlat's avatar
Simon Morlat committed
1 2
/*
	belle-sip - SIP (RFC3261) library.
3
	Copyright (C) 2013  Belledonne Communications SARL
Simon Morlat's avatar
Simon Morlat committed
4

5 6
	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
7
	the Free Software Foundation, either version 2 of the License, or
8
	(at your option) any later version.
Simon Morlat's avatar
Simon Morlat committed
9

10 11 12 13
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
Simon Morlat's avatar
Simon Morlat committed
14

15 16
	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
Simon Morlat's avatar
Simon Morlat committed
17 18 19 20 21
*/


#include "belle_sip_internal.h"

Simon Morlat's avatar
Simon Morlat committed
22 23 24 25
typedef struct belle_http_channel_context belle_http_channel_context_t;

#define BELLE_HTTP_CHANNEL_CONTEXT(obj) BELLE_SIP_CAST(obj,belle_http_channel_context_t)

Simon Morlat's avatar
Simon Morlat committed
26 27
static void provider_remove_channel(belle_http_provider_t *obj, belle_sip_channel_t *chan);

Simon Morlat's avatar
Simon Morlat committed
28 29
struct belle_http_channel_context{
	belle_sip_object_t base;
Simon Morlat's avatar
Simon Morlat committed
30
	belle_http_provider_t *provider;
Simon Morlat's avatar
Simon Morlat committed
31 32
	belle_sip_list_t *pending_requests;
};
Simon Morlat's avatar
Simon Morlat committed
33 34

struct belle_http_provider{
Simon Morlat's avatar
Simon Morlat committed
35
	belle_sip_object_t base;
Simon Morlat's avatar
Simon Morlat committed
36
	belle_sip_stack_t *stack;
Simon Morlat's avatar
Simon Morlat committed
37
	char *bind_ip;
Simon Morlat's avatar
Simon Morlat committed
38
	int ai_family;
Simon Morlat's avatar
Simon Morlat committed
39 40
	belle_sip_list_t *tcp_channels;
	belle_sip_list_t *tls_channels;
41
	belle_tls_verify_policy_t *verify_ctx;
Simon Morlat's avatar
Simon Morlat committed
42 43
};

Simon Morlat's avatar
Simon Morlat committed
44 45 46
#define BELLE_HTTP_REQUEST_INVOKE_LISTENER(obj,method,arg) \
	obj->listener ? BELLE_SIP_INVOKE_LISTENER_ARG(obj->listener,belle_http_request_listener_t,method,arg) : 0

47 48 49 50 51 52
static int http_channel_context_handle_authentication(belle_http_channel_context_t *ctx, belle_http_request_t *req){
	const char *realm=NULL;
	belle_sip_auth_event_t *ev=NULL;
	belle_http_response_t *resp=belle_http_request_get_response(req);
	const char *username=NULL;
	const char *passwd=NULL;
jehan's avatar
jehan committed
53 54 55
	const char *ha1=NULL;
	char computed_ha1[33];
	belle_sip_header_www_authenticate_t* authenticate;
56
	int ret=0;
57

jehan's avatar
jehan committed
58

Simon Morlat's avatar
Simon Morlat committed
59 60 61 62
	if (req->auth_attempt_count>1){
		req->auth_attempt_count=0;
		return -1;
	}
jehan's avatar
jehan committed
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
	if (resp == NULL ) {
		belle_sip_error("Missing response for  req [%p], cannot authenticate", req);
		return -1;
	}
	if (!(authenticate = belle_sip_message_get_header_by_type(resp,belle_sip_header_www_authenticate_t))) {
		if (belle_sip_message_get_header_by_type(resp,belle_sip_header_proxy_authenticate_t)) {
			belle_sip_error("Proxy authentication not supported yet, cannot authenticate for resp [%p]", resp);
		}
		belle_sip_error("Missing auth header in response  [%p], cannot authenticate", resp);
		return -1;
	}


	if (strcasecmp("Digest",belle_sip_header_www_authenticate_get_scheme(authenticate)) != 0) {
		belle_sip_error("Unsupported auth scheme [%s] in response  [%p], cannot authenticate", belle_sip_header_www_authenticate_get_scheme(authenticate),resp);
		return -1;
	}

81 82 83 84 85
	/*find if username, passwd were already supplied in original request uri*/
	if (req->orig_uri){
		username=belle_generic_uri_get_user(req->orig_uri);
		passwd=belle_generic_uri_get_user_password(req->orig_uri);
	}
jehan's avatar
jehan committed
86 87 88

	realm = belle_sip_header_www_authenticate_get_realm(authenticate);
	if (!username || !passwd) {
89 90 91 92
		ev=belle_sip_auth_event_create((belle_sip_object_t*)ctx->provider,realm,NULL);
		BELLE_HTTP_REQUEST_INVOKE_LISTENER(req,process_auth_requested,ev);
		username=ev->username;
		passwd=ev->passwd;
jehan's avatar
jehan committed
93 94 95 96 97 98 99 100
		ha1=ev->ha1;
	}
	if (!ha1 && username  && passwd) {
		belle_sip_auth_helper_compute_ha1(username,realm,passwd, computed_ha1);
		ha1=computed_ha1;
	} else if (!ha1){
		belle_sip_error("No auth info found for request [%p], cannot authenticate",req);
		ret=-1;
101
	}
102

jehan's avatar
jehan committed
103 104
	if (ha1) {
		belle_http_header_authorization_t* authorization;
Simon Morlat's avatar
Simon Morlat committed
105
		req->auth_attempt_count++;
jehan's avatar
jehan committed
106 107

		authorization = belle_http_auth_helper_create_authorization(authenticate);
jehan's avatar
jehan committed
108 109 110 111
		/*select first qop mode*/
		belle_sip_header_authorization_set_qop(BELLE_SIP_HEADER_AUTHORIZATION(authorization),belle_sip_header_www_authenticate_get_qop_first(authenticate));
		belle_sip_header_authorization_set_nonce_count(BELLE_SIP_HEADER_AUTHORIZATION(authorization),1); /*we don't store nonce count for now*/
		belle_sip_header_authorization_set_username(BELLE_SIP_HEADER_AUTHORIZATION(authorization),username);
jehan's avatar
jehan committed
112 113 114 115 116 117
		belle_http_header_authorization_set_uri(authorization,belle_http_request_get_uri(req));
		if (belle_sip_auth_helper_fill_authorization(BELLE_SIP_HEADER_AUTHORIZATION(authorization),belle_http_request_get_method(req),ha1)) {
			belle_sip_error("Cannot fill auth header for request [%p]",req);
			if (authorization) belle_sip_object_unref(authorization);
			ret=-1;
		} else {
118
			belle_sip_message_remove_header(BELLE_SIP_MESSAGE(req),BELLE_HTTP_AUTHORIZATION);
jehan's avatar
jehan committed
119 120 121 122 123
			belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(authorization));
			belle_http_provider_send_request(ctx->provider,req,NULL);
		}

	}
124 125 126
	if (ev) belle_sip_auth_event_destroy(ev);
	return ret;
}
127 128 129 130 131

static void http_channel_context_handle_response_headers(belle_http_channel_context_t *ctx , belle_sip_channel_t *chan, belle_http_response_t *response){
	belle_http_request_t *req=ctx->pending_requests ? (belle_http_request_t*) ctx->pending_requests->data : NULL;
	belle_http_response_event_t ev={0};
	int code;
132

133 134 135 136
	if (req==NULL){
		belle_sip_error("Receiving http response headers not matching any request.");
		return;
	}
137 138 139 140
	if (belle_http_request_is_cancelled(req)) {
		belle_sip_warning("Receiving http response headers for a cancelled request.");
		return;
	}
141 142 143 144 145 146 147 148 149 150
	code=belle_http_response_get_status_code(response);
	if (code!=401 && code!=407){
		/*else notify the app about the response headers received*/
		ev.source=(belle_sip_object_t*)ctx->provider;
		ev.request=req;
		ev.response=response;
		BELLE_HTTP_REQUEST_INVOKE_LISTENER(req,process_response_headers,&ev);
	}
}

Simon Morlat's avatar
Simon Morlat committed
151
static void http_channel_context_handle_response(belle_http_channel_context_t *ctx , belle_sip_channel_t *chan, belle_http_response_t *response){
152 153 154
	belle_http_request_t *req=NULL;
	belle_http_response_event_t ev={0};
	int code;
Simon Morlat's avatar
Simon Morlat committed
155
	belle_sip_header_t *connection;
156 157 158 159 160 161
	/*pop the request matching this response*/
	ctx->pending_requests=belle_sip_list_pop_front(ctx->pending_requests,(void**)&req);
	if (req==NULL){
		belle_sip_error("Receiving http response not matching any request.");
		return;
	}
162 163 164 165
	if (belle_http_request_is_cancelled(req)) {
		belle_sip_warning("Receiving http response for a cancelled request.");
		return;
	}
Simon Morlat's avatar
Simon Morlat committed
166 167 168
	connection=belle_sip_message_get_header((belle_sip_message_t *)response,"Connection");
	if (connection && strstr(belle_sip_header_get_unparsed_value(connection),"close")!=NULL)
		chan->about_to_be_closed=TRUE;
169

170 171 172 173 174 175 176 177 178 179
	belle_http_request_set_response(req,response);
	code=belle_http_response_get_status_code(response);
	if ((code==401 || code==407) && http_channel_context_handle_authentication(ctx,req)==0 ){
		/*nothing to do, the request has been resubmitted with authentication*/
	}else{
		/*else notify the app about the response received*/
		ev.source=(belle_sip_object_t*)ctx->provider;
		ev.request=req;
		ev.response=response;
		BELLE_HTTP_REQUEST_INVOKE_LISTENER(req,process_response,&ev);
180 181 182 183 184
		if( req->background_task_id ){
			belle_sip_warning("HTTP request finished: ending bg task id=[%x]", req->background_task_id);
			belle_sip_end_background_task(req->background_task_id);
			req->background_task_id = 0;
		}
185 186 187 188
	}
	belle_sip_object_unref(req);
}

189 190 191 192
static void http_channel_context_handle_io_error(belle_http_channel_context_t *ctx, belle_sip_channel_t *chan){
	belle_http_request_t *req=NULL;
	belle_sip_io_error_event_t ev={0};
	belle_sip_list_t *elem;
193

194 195 196 197 198 199 200 201 202 203 204 205 206
	/*if the error happens before attempting to send the message, the pending_requests is empty*/
	if (ctx->pending_requests==NULL) elem=chan->outgoing_messages;
	else elem=ctx->pending_requests;
	/*pop the requests for which this error is reported*/
	for(;elem!=NULL;elem=elem->next){
		req=(belle_http_request_t *)elem->data;
		/*else notify the app about the response received*/
		/*TODO: would be nice to put the message in the event*/
		ev.source=(belle_sip_object_t*)ctx->provider;
		ev.host=chan->peer_cname;
		ev.port=chan->peer_port;
		ev.transport=belle_sip_channel_get_transport_name(chan);
		BELLE_HTTP_REQUEST_INVOKE_LISTENER(req,process_io_error,&ev);
207 208 209 210 211
		if( req->background_task_id ){
			belle_sip_warning("IO Error on HTTP request: ending bg task id=[%x]", req->background_task_id);
			belle_sip_end_background_task(req->background_task_id);
			req->background_task_id = 0;
		}
212
	}
213

214 215
}

216 217 218 219
/* we are called here by the channel when receiving a message for which a body is expected.
 * We can notify the application so that it can setup an appropriate body handler.
 */
static void channel_on_message_headers(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_message_t *msg){
Simon Morlat's avatar
Simon Morlat committed
220
	belle_http_channel_context_t *ctx=BELLE_HTTP_CHANNEL_CONTEXT(obj);
221

222 223 224 225 226 227 228
	if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(msg,belle_http_response_t)){
		http_channel_context_handle_response_headers(ctx,chan,(belle_http_response_t*)msg);
	}/*ignore requests*/
}

static void channel_on_message(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_message_t *msg){
	belle_http_channel_context_t *ctx=BELLE_HTTP_CHANNEL_CONTEXT(obj);
229

230 231 232
	if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(msg,belle_http_response_t)){
		http_channel_context_handle_response(ctx,chan,(belle_http_response_t*)msg);
	}/*ignore requests*/
Simon Morlat's avatar
Simon Morlat committed
233 234 235
}

static int channel_on_auth_requested(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, const char* distinguished_name){
236
	belle_http_channel_context_t *ctx=BELLE_HTTP_CHANNEL_CONTEXT(obj);
Simon Morlat's avatar
Simon Morlat committed
237
	if (BELLE_SIP_IS_INSTANCE_OF(chan,belle_sip_tls_channel_t)) {
238
		belle_sip_auth_event_t* auth_event = belle_sip_auth_event_create((belle_sip_object_t*)ctx->provider,NULL,NULL);
Simon Morlat's avatar
Simon Morlat committed
239
		belle_sip_tls_channel_t *tls_chan=BELLE_SIP_TLS_CHANNEL(chan);
Simon Morlat's avatar
Simon Morlat committed
240
		belle_http_request_t *req=(belle_http_request_t*)chan->outgoing_messages->data;
Simon Morlat's avatar
Simon Morlat committed
241 242
		auth_event->mode=BELLE_SIP_AUTH_MODE_TLS;
		belle_sip_auth_event_set_distinguished_name(auth_event,distinguished_name);
243

244
		BELLE_HTTP_REQUEST_INVOKE_LISTENER(req,process_auth_requested,auth_event);
Simon Morlat's avatar
Simon Morlat committed
245 246 247 248 249 250 251 252
		belle_sip_tls_channel_set_client_certificates_chain(tls_chan,auth_event->cert);
		belle_sip_tls_channel_set_client_certificate_key(tls_chan,auth_event->key);
		belle_sip_auth_event_destroy(auth_event);
	}
	return 0;
}

static void channel_on_sending(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_message_t *msg){
Simon Morlat's avatar
Simon Morlat committed
253
	belle_http_channel_context_t *ctx=BELLE_HTTP_CHANNEL_CONTEXT(obj);
Simon Morlat's avatar
Simon Morlat committed
254
	ctx->pending_requests=belle_sip_list_append(ctx->pending_requests,belle_sip_object_ref(msg));
Simon Morlat's avatar
Simon Morlat committed
255 256 257
}

static void channel_state_changed(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_channel_state_t state){
Simon Morlat's avatar
Simon Morlat committed
258
	belle_http_channel_context_t *ctx=BELLE_HTTP_CHANNEL_CONTEXT(obj);
Simon Morlat's avatar
Simon Morlat committed
259 260 261 262 263 264 265 266 267
	switch(state){
		case BELLE_SIP_CHANNEL_INIT:
		case BELLE_SIP_CHANNEL_RES_IN_PROGRESS:
		case BELLE_SIP_CHANNEL_RES_DONE:
		case BELLE_SIP_CHANNEL_CONNECTING:
		case BELLE_SIP_CHANNEL_READY:
		case BELLE_SIP_CHANNEL_RETRY:
			break;
		case BELLE_SIP_CHANNEL_ERROR:
268
			http_channel_context_handle_io_error(ctx, chan);
Simon Morlat's avatar
Simon Morlat committed
269
		case BELLE_SIP_CHANNEL_DISCONNECTED:
Simon Morlat's avatar
Simon Morlat committed
270
			if (!chan->force_close) provider_remove_channel(ctx->provider,chan);
Simon Morlat's avatar
Simon Morlat committed
271 272
			break;
	}
Simon Morlat's avatar
Simon Morlat committed
273 274
}

Simon Morlat's avatar
Simon Morlat committed
275
static void belle_http_channel_context_uninit(belle_http_channel_context_t *obj){
Simon Morlat's avatar
Simon Morlat committed
276
	belle_sip_list_free_with_data(obj->pending_requests,belle_sip_object_unref);
Simon Morlat's avatar
Simon Morlat committed
277 278
}

Simon Morlat's avatar
Simon Morlat committed
279 280 281 282 283 284 285 286 287 288
static void on_channel_destroyed(belle_http_channel_context_t *obj, belle_sip_channel_t *chan_being_destroyed){
	belle_sip_channel_remove_listener(chan_being_destroyed,BELLE_SIP_CHANNEL_LISTENER(obj));
	belle_sip_object_unref(obj);
}

/*
 * The http channel context stores pending requests so that they can be matched with response received.
 * It is associated with the channel when the channel is created, and automatically destroyed when the channel is destroyed.
**/
belle_http_channel_context_t * belle_http_channel_context_new(belle_sip_channel_t *chan, belle_http_provider_t *prov){
Simon Morlat's avatar
Simon Morlat committed
289
	belle_http_channel_context_t *obj=belle_sip_object_new(belle_http_channel_context_t);
Simon Morlat's avatar
Simon Morlat committed
290
	obj->provider=prov;
Simon Morlat's avatar
Simon Morlat committed
291
	belle_sip_channel_add_listener(chan,(belle_sip_channel_listener_t*)obj);
Simon Morlat's avatar
Simon Morlat committed
292
	belle_sip_object_weak_ref(chan,(belle_sip_object_destroy_notify_t)on_channel_destroyed,obj);
Simon Morlat's avatar
Simon Morlat committed
293 294
	return obj;
}
Simon Morlat's avatar
Simon Morlat committed
295

Simon Morlat's avatar
Simon Morlat committed
296
BELLE_SIP_IMPLEMENT_INTERFACE_BEGIN(belle_http_channel_context_t,belle_sip_channel_listener_t)
Simon Morlat's avatar
Simon Morlat committed
297
	channel_state_changed,
298 299
	channel_on_message_headers,
	channel_on_message,
Simon Morlat's avatar
Simon Morlat committed
300 301 302 303
	channel_on_sending,
	channel_on_auth_requested
BELLE_SIP_IMPLEMENT_INTERFACE_END

Simon Morlat's avatar
Simon Morlat committed
304 305
BELLE_SIP_DECLARE_IMPLEMENTED_INTERFACES_1(belle_http_channel_context_t,belle_sip_channel_listener_t);
BELLE_SIP_INSTANCIATE_VPTR(belle_http_channel_context_t,belle_sip_object_t,belle_http_channel_context_uninit,NULL,NULL,FALSE);
Simon Morlat's avatar
Simon Morlat committed
306 307

static void http_provider_uninit(belle_http_provider_t *obj){
308
	belle_sip_message("http provider destroyed.");
Simon Morlat's avatar
Simon Morlat committed
309
	belle_sip_free(obj->bind_ip);
Simon Morlat's avatar
Simon Morlat committed
310 311 312 313
	belle_sip_list_for_each(obj->tcp_channels,(void (*)(void*))belle_sip_channel_force_close);
	belle_sip_list_free_with_data(obj->tcp_channels,belle_sip_object_unref);
	belle_sip_list_for_each(obj->tls_channels,(void (*)(void*))belle_sip_channel_force_close);
	belle_sip_list_free_with_data(obj->tls_channels,belle_sip_object_unref);
314
	belle_sip_object_unref(obj->verify_ctx);
Simon Morlat's avatar
Simon Morlat committed
315 316
}

Simon Morlat's avatar
Simon Morlat committed
317
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_http_provider_t);
Simon Morlat's avatar
Simon Morlat committed
318 319
BELLE_SIP_INSTANCIATE_VPTR(belle_http_provider_t,belle_sip_object_t,http_provider_uninit,NULL,NULL,FALSE);

Simon Morlat's avatar
Simon Morlat committed
320
belle_http_provider_t *belle_http_provider_new(belle_sip_stack_t *s, const char *bind_ip){
Simon Morlat's avatar
Simon Morlat committed
321
	belle_http_provider_t *p=belle_sip_object_new(belle_http_provider_t);
Simon Morlat's avatar
Simon Morlat committed
322
	p->stack=s;
Simon Morlat's avatar
Simon Morlat committed
323
	p->bind_ip=belle_sip_strdup(bind_ip);
Simon Morlat's avatar
Simon Morlat committed
324
	p->ai_family=strchr(p->bind_ip,':') ? AF_INET6 : AF_INET;
325
	p->verify_ctx=belle_tls_verify_policy_new();
Simon Morlat's avatar
Simon Morlat committed
326 327
	return p;
}
Simon Morlat's avatar
Simon Morlat committed
328

Simon Morlat's avatar
Simon Morlat committed
329 330
static void split_request_url(belle_http_request_t *req){
	belle_generic_uri_t *uri=belle_http_request_get_uri(req);
Simon Morlat's avatar
Simon Morlat committed
331
	belle_generic_uri_t *new_uri;
Simon Morlat's avatar
Simon Morlat committed
332
	char *host_value;
Simon Morlat's avatar
Simon Morlat committed
333
	const char *path;
334

Simon Morlat's avatar
Simon Morlat committed
335 336 337 338 339 340
	if (belle_generic_uri_get_host(uri)==NULL && req->orig_uri!=NULL) return;/*already processed request uri*/
	path=belle_generic_uri_get_path(uri);
	if (path==NULL) path="/";
	new_uri=belle_generic_uri_new();

	belle_generic_uri_set_path(new_uri,path);
341
	belle_generic_uri_set_query(new_uri, belle_generic_uri_get_query(uri));
Simon Morlat's avatar
Simon Morlat committed
342 343
	if (belle_generic_uri_get_port(uri)>0)
		host_value=belle_sip_strdup_printf("%s:%i",belle_generic_uri_get_host(uri),belle_generic_uri_get_port(uri));
344
	else
Simon Morlat's avatar
Simon Morlat committed
345 346 347
		host_value=belle_sip_strdup(belle_generic_uri_get_host(uri));
	belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Host",host_value));
	belle_sip_free(host_value);
348
	SET_OBJECT_PROPERTY(req,orig_uri,uri);
Simon Morlat's avatar
Simon Morlat committed
349 350 351
	belle_http_request_set_uri(req,new_uri);
}

Simon Morlat's avatar
Simon Morlat committed
352 353 354 355 356 357 358 359
static void fix_request(belle_http_request_t *req){
	unsigned int size=belle_sip_message_get_body_size((belle_sip_message_t*)req);
	belle_sip_header_content_length_t *ctlen=belle_sip_message_get_header_by_type(req, belle_sip_header_content_length_t);
	if (size>0 && !ctlen){
		belle_sip_message_add_header((belle_sip_message_t*)req,(belle_sip_header_t*)belle_sip_header_content_length_create((int)size));
	}
}

Simon Morlat's avatar
Simon Morlat committed
360 361 362
static belle_sip_list_t **provider_get_channels(belle_http_provider_t *obj, const char *transport_name){
	if (strcasecmp(transport_name,"tcp")==0) return &obj->tcp_channels;
	else if (strcasecmp(transport_name,"tls")==0) return &obj->tls_channels;
Simon Morlat's avatar
Simon Morlat committed
363
	else{
Simon Morlat's avatar
Simon Morlat committed
364 365
		belle_sip_error("belle_http_provider_send_request(): unsupported transport %s",transport_name);
		return NULL;
Simon Morlat's avatar
Simon Morlat committed
366
	}
Simon Morlat's avatar
Simon Morlat committed
367 368 369 370 371
}

static void provider_remove_channel(belle_http_provider_t *obj, belle_sip_channel_t *chan){
	belle_sip_list_t **channels=provider_get_channels(obj,belle_sip_channel_get_transport_name(chan));
	*channels=belle_sip_list_remove(*channels,chan);
Simon Morlat's avatar
Simon Morlat committed
372
	belle_sip_message("channel [%p] removed from http provider.",obj);
Simon Morlat's avatar
Simon Morlat committed
373 374 375
	belle_sip_object_unref(chan);
}

376 377 378 379 380 381 382 383 384
static void belle_http_end_background_task(void* data) {
	belle_http_request_t *req = BELLE_HTTP_REQUEST(data);
	belle_sip_warning("Ending unfinished HTTP transfer background task id=[%x]", req->background_task_id);
	if( req->background_task_id ){
		belle_sip_end_background_task(req->background_task_id);
		req->background_task_id = 0;
	}
}

Simon Morlat's avatar
Simon Morlat committed
385 386
int belle_http_provider_send_request(belle_http_provider_t *obj, belle_http_request_t *req, belle_http_request_listener_t *listener){
	belle_sip_channel_t *chan;
Simon Morlat's avatar
Simon Morlat committed
387
	belle_sip_hop_t *hop=belle_sip_hop_new_from_generic_uri(req->orig_uri ? req->orig_uri : req->req_uri);
Simon Morlat's avatar
Simon Morlat committed
388
	belle_sip_list_t **channels=provider_get_channels(obj,hop->transport);
389

390
	if (listener) belle_http_request_set_listener(req,listener);
391

Simon Morlat's avatar
Simon Morlat committed
392
	chan=belle_sip_channel_find_from_list(*channels,obj->ai_family, hop);
393

Simon Morlat's avatar
Simon Morlat committed
394
	if (!chan){
395 396
		if (strcasecmp(hop->transport,"tcp")==0){
			chan=belle_sip_stream_channel_new_client(obj->stack,obj->bind_ip,0,hop->cname,hop->host,hop->port);
Simon Morlat's avatar
Simon Morlat committed
397 398 399
		}
#ifdef HAVE_POLARSSL
		else if (strcasecmp(hop->transport,"tls")==0){
400 401
			chan=belle_sip_channel_new_tls(obj->stack,obj->verify_ctx,obj->bind_ip,0,hop->cname,hop->host,hop->port);
		}
Simon Morlat's avatar
Simon Morlat committed
402 403 404 405 406 407
#endif
		if (!chan){
			belle_sip_error("belle_http_provider_send_request(): cannot create channel for [%s:%s:%i]",hop->transport,hop->cname,hop->port);
			belle_sip_object_unref(hop);
			return -1;
		}
Simon Morlat's avatar
Simon Morlat committed
408
		belle_http_channel_context_new(chan,obj);
Simon Morlat's avatar
Simon Morlat committed
409 410 411
		*channels=belle_sip_list_prepend(*channels,chan);
	}
	belle_sip_object_unref(hop);
Simon Morlat's avatar
Simon Morlat committed
412
	split_request_url(req);
Simon Morlat's avatar
Simon Morlat committed
413
	fix_request(req);
414

415
	belle_http_request_set_channel(req,chan);
416
	if( req->background_task_id != 0){
417
		req->background_task_id = belle_sip_begin_background_task("belle-sip http", belle_http_end_background_task, req);
418 419
	}

Simon Morlat's avatar
Simon Morlat committed
420 421
	belle_sip_channel_queue_message(chan,BELLE_SIP_MESSAGE(req));
	return 0;
Simon Morlat's avatar
Simon Morlat committed
422 423
}

424 425 426 427 428 429 430 431 432 433 434
static void reenqueue_request(belle_http_request_t *req, belle_http_provider_t *prov){
	belle_http_provider_send_request(prov,req,req->listener);
}

void belle_http_provider_cancel_request(belle_http_provider_t *obj, belle_http_request_t *req){
	belle_sip_list_t *outgoing_messages;

	belle_http_request_cancel(req);
	if (req->channel){
		// Keep the list of the outgoing messages of the channel...
		outgoing_messages = belle_sip_list_copy_with_data(req->channel->outgoing_messages,(void* (*)(void*))belle_sip_object_ref);
Simon Morlat's avatar
Simon Morlat committed
435 436
		/*protect the channel from being destroyed before removing it (removing it will unref it)*/
		belle_sip_object_ref(req->channel);
437 438 439
		provider_remove_channel(obj, req->channel);
		// ... close the channel...
		belle_sip_channel_force_close(req->channel);
Simon Morlat's avatar
Simon Morlat committed
440
		belle_sip_object_unref(req->channel);
441 442 443 444 445 446
		// ... and reenqueue the previously queued outgoing messages into a new channel
		belle_sip_list_for_each2(outgoing_messages,(void (*)(void*,void*))reenqueue_request,obj);
		belle_sip_list_free_with_data(outgoing_messages,belle_sip_object_unref);
	}
}

447 448 449 450 451 452
int belle_http_provider_set_tls_verify_policy(belle_http_provider_t *obj, belle_tls_verify_policy_t *verify_ctx){
	SET_OBJECT_PROPERTY(obj,verify_ctx,verify_ctx);
	return 0;
}