diff options
Diffstat (limited to 'protocols/http_client.c')
| -rw-r--r-- | protocols/http_client.c | 115 | 
1 files changed, 92 insertions, 23 deletions
| diff --git a/protocols/http_client.c b/protocols/http_client.c index 9417e200..c793d9d4 100644 --- a/protocols/http_client.c +++ b/protocols/http_client.c @@ -70,6 +70,37 @@ void *http_dorequest( char *host, int port, int ssl, char *request, http_input_f  	return( req );  } +void *http_dorequest_url( char *url_string, http_input_function func, gpointer data ) +{ +	url_t *url = g_new0( url_t, 1 ); +	char *request; +	void *ret; +	 +	if( !url_set( url, url_string ) ) +	{ +		g_free( url ); +		return NULL; +	} +	 +	if( url->proto != PROTO_HTTP && url->proto != PROTO_HTTPS ) +	{ +		g_free( url ); +		return NULL; +	} +	 +	request = g_strdup_printf( "GET %s HTTP/1.0\r\n" +	                           "Host: %s\r\n" +	                           "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n" +	                           "\r\n", url->file, url->host ); +	 +	ret = http_dorequest( url->host, url->port, +	                      url->proto == PROTO_HTTPS, request, func, data ); +	 +	g_free( url ); +	g_free( request ); +	return ret; +} +  /* This one is actually pretty simple... Might get more calls if we can't write      the whole request at once. */  static void http_connected( gpointer data, int source, GaimInputCondition cond ) @@ -125,6 +156,8 @@ static void http_connected( gpointer data, int source, GaimInputCondition cond )  	return;  error: +	req->status_string = g_strdup( "Error while writing HTTP request" ); +	  	req->func( req );  	g_free( req->request ); @@ -184,6 +217,7 @@ static void http_incoming_data( gpointer data, int source, GaimInputCondition co  		{  			if( !sockerr_again() )  			{ +				req->status_string = g_strdup( strerror( errno ) );  				goto cleanup;  			}  		} @@ -208,6 +242,14 @@ static void http_incoming_data( gpointer data, int source, GaimInputCondition co  	return;  got_reply: +	/* Maybe if the webserver is overloaded, or when there's bad SSL +	   support... */ +	if( req->bytes_read == 0 ) +	{ +		req->status_string = g_strdup( "Empty HTTP reply" ); +		goto cleanup; +	} +	  	/* Zero termination is very convenient. */  	req->reply_headers[req->bytes_read] = 0; @@ -221,28 +263,53 @@ got_reply:  		end1 = end2 + 1;  		evil_server = 1;  	} -	else +	else if( end1 )  	{  		end1 += 2;  	} -	 -	if( end1 ) +	else  	{ -		*end1 = 0; -		 -		if( evil_server ) -			req->reply_body = end1 + 1; -		else -			req->reply_body = end1 + 2; +		req->status_string = g_strdup( "Malformed HTTP reply" ); +		goto cleanup;  	} +	*end1 = 0; +	 +	if( evil_server ) +		req->reply_body = end1 + 1; +	else +		req->reply_body = end1 + 2; +	 +	req->body_size = req->reply_headers + req->bytes_read - req->reply_body; +	  	if( ( end1 = strchr( req->reply_headers, ' ' ) ) != NULL )  	{  		if( sscanf( end1 + 1, "%d", &req->status_code ) != 1 ) +		{ +			req->status_string = g_strdup( "Can't parse status code" );  			req->status_code = -1; +		} +		else +		{ +			char *eol; +			 +			if( evil_server ) +				eol = strchr( end1, '\n' ); +			else +				eol = strchr( end1, '\r' ); +			 +			req->status_string = g_strndup( end1 + 1, eol - end1 - 1 ); +			 +			/* Just to be sure... */ +			if( ( eol = strchr( req->status_string, '\r' ) ) ) +				*eol = 0; +			if( ( eol = strchr( req->status_string, '\n' ) ) ) +				*eol = 0; +		}  	}  	else  	{ +		req->status_string = g_strdup( "Can't locate status code" );  		req->status_code = -1;  	} @@ -251,9 +318,16 @@ got_reply:  		char *loc, *new_request, *new_host;  		int error = 0, new_port, new_proto; +		/* We might fill it again, so let's not leak any memory. */ +		g_free( req->status_string ); +		req->status_string = NULL; +		  		loc = strstr( req->reply_headers, "\nLocation: " );  		if( loc == NULL ) /* We can't handle this redirect... */ +		{ +			req->status_string = g_strdup( "Can't locate Location: header" );  			goto cleanup; +		}  		loc += 11;  		while( *loc == ' ' ) @@ -270,6 +344,8 @@ got_reply:  			/* Since we don't cache the servername, and since we  			   don't need this yet anyway, I won't implement it. */ +			req->status_string = g_strdup( "Can't handle recursive redirects" ); +			  			goto cleanup;  		}  		else @@ -287,6 +363,7 @@ got_reply:  			if( !url_set( url, loc ) )  			{ +				req->status_string = g_strdup( "Malformed redirect URL" );  				g_free( url );  				goto cleanup;  			} @@ -297,28 +374,18 @@ got_reply:  			/* So, now I just allocated enough memory, so I'm  			   going to use strcat(), whether you like it or not. :-) */ -			/* First, find the GET/POST/whatever from the original request. */ -			s = strchr( req->request, ' ' ); -			if( s == NULL ) -			{ -				g_free( new_request ); -				g_free( url ); -				goto cleanup; -			} -			 -			*s = 0; -			sprintf( new_request, "%s %s HTTP/1.0\r\n", req->request, url->file ); -			*s = ' '; +			sprintf( new_request, "GET %s HTTP/1.0", url->file );  			s = strstr( req->request, "\r\n" );  			if( s == NULL )  			{ +				req->status_string = g_strdup( "Error while rebuilding request string" );  				g_free( new_request );  				g_free( url );  				goto cleanup;  			} -			strcat( new_request, s + 2 ); +			strcat( new_request, s );  			new_host = g_strdup( url->host );  			new_port = url->port;  			new_proto = url->proto; @@ -332,7 +399,7 @@ got_reply:  			closesocket( req->fd );  		req->fd = -1; -		req->ssl = 0; +		req->ssl = NULL;  		if( new_proto == PROTO_HTTPS )  		{ @@ -350,6 +417,7 @@ got_reply:  		if( error )  		{ +			req->status_string = g_strdup( "Connection problem during redirect" );  			g_free( new_request );  			goto cleanup;  		} @@ -378,5 +446,6 @@ cleanup:  	g_free( req->request );  	g_free( req->reply_headers ); +	g_free( req->status_string );  	g_free( req );  } | 
