source: protocols/http_client.c @ 8a9afe4

Last change on this file since 8a9afe4 was 8a9afe4, checked in by Wilmer van der Gaast <wilmer@…>, at 2005-12-17T16:54:12Z

http_client lib

  • Property mode set to 100644
File size: 5.4 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2005 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* HTTP(S) module (actually, it only does HTTPS right now)              */
8
9/*
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License with
21  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23  Suite 330, Boston, MA  02111-1307  USA
24*/
25
26#include <string.h>
27
28#include "sock.h"
29#include "http_client.h"
30
31
32static void http_connected( gpointer data, int source, GaimInputCondition cond );
33static void http_ssl_connected( gpointer data, void *source, GaimInputCondition cond );
34static void http_incoming_data( gpointer data, int source, GaimInputCondition cond );
35
36
37void *http_dorequest( char *host, int port, http_input_function func, int ssl, char *request, gpointer data )
38{
39        struct http_request *req;
40        int error = 0;
41       
42        req = g_new0( struct http_request, 1 );
43       
44        if( ssl )
45        {
46                req->ssl = ssl_connect( host, port, http_ssl_connected, req );
47                if( req->ssl == NULL )
48                        error = 1;
49        }
50        else
51        {
52                req->fd = proxy_connect( host, port, http_connected, req );
53                if( req->fd < 0 )
54                        error = 1;
55        }
56       
57        if( error )
58        {
59                g_free( req );
60                return( NULL );
61        }
62       
63        req->request = g_strdup( request );
64        req->request_length = strlen( request );
65       
66        return( req );
67}
68
69/* This one is actually pretty simple... Might get more calls if we can't write
70   the whole request at once. */
71static void http_connected( gpointer data, int source, GaimInputCondition cond )
72{
73        struct http_request *req = data;
74        int st;
75       
76        if( source < 0 )
77                goto error;
78       
79        if( req->inpa > 0 )
80                gaim_input_remove( req->inpa );
81       
82        sock_make_nonblocking( req->fd );
83       
84        if( req->ssl )
85        {
86                st = ssl_write( req->ssl, req->request + req->bytes_written,
87                                req->request_length - req->bytes_written );
88                if( st < 0 )
89                {
90                        if( ssl_errno != SSL_AGAIN )
91                        {
92                                ssl_disconnect( req->ssl );
93                                goto error;
94                        }
95                }
96        }
97        else
98        {
99                st = write( source, req->request + req->bytes_written,
100                                    req->request_length - req->bytes_written );
101                if( st < 0 )
102                {
103                        if( !sockerr_again() )
104                        {
105                                close( req->fd );
106                                goto error;
107                        }
108                }
109        }
110       
111        if( st > 0 )
112                req->bytes_written += st;
113       
114        if( req->bytes_written < req->request_length )
115                req->inpa = gaim_input_add( source,
116                                            req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_WRITE,
117                                            http_connected, req );
118        else
119                req->inpa = gaim_input_add( source, GAIM_INPUT_READ, http_incoming_data, req );
120       
121        return;
122       
123error:
124        req->func( req );
125       
126        g_free( req->request );
127        g_free( req );
128       
129        return;
130}
131
132static void http_ssl_connected( gpointer data, void *source, GaimInputCondition cond )
133{
134        struct http_request *req = data;
135       
136        if( source == NULL )
137                return http_connected( data, -1, cond );
138       
139        req->fd = ssl_getfd( source );
140       
141        return http_connected( data, req->fd, cond );
142}
143
144static void http_incoming_data( gpointer data, int source, GaimInputCondition cond )
145{
146        struct http_request *req = data;
147        int evil_server = 0;
148        char buffer[2048];
149        char *end1, *end2;
150        int st;
151       
152        if( req->inpa > 0 )
153                gaim_input_remove( req->inpa );
154       
155        if( req->ssl )
156        {
157                st = ssl_read( req->ssl, buffer, sizeof( buffer ) );
158                if( st < 0 )
159                {
160                        if( ssl_errno != SSL_AGAIN )
161                        {
162                                goto cleanup;
163                        }
164                }
165                else if( st == 0 )
166                {
167                        goto got_reply;
168                }
169        }
170        else
171        {
172                st = read( req->fd, buffer, sizeof( buffer ) );
173                if( st < 0 )
174                {
175                        if( !sockerr_again() )
176                        {
177                                goto cleanup;
178                        }
179                }
180                else if( st == 0 )
181                {
182                        goto got_reply;
183                }
184        }
185       
186        if( st > 0 )
187        {
188                req->reply_headers = g_realloc( req->reply_headers, req->bytes_read + st + 1 );
189                memcpy( req->reply_headers + req->bytes_read, buffer, st );
190        }
191       
192        /* There will be more! */
193        req->inpa = gaim_input_add( req->fd,
194                                    req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_READ,
195                                    http_incoming_data, req );
196       
197        return;
198
199got_reply:
200        /* Zero termination is very convenient. */
201        req->reply_headers[req->bytes_read] = 0;
202       
203        /* Find the separation between headers and body, and keep stupid
204           webservers in mind. */
205        end1 = strstr( req->reply_headers, "\r\n\r\n" );
206        end2 = strstr( req->reply_headers, "\n\n" );
207       
208        if( end2 && end2 < end1 )
209        {
210                end1 = end2;
211                evil_server = 1;
212        }
213       
214        if( end1 )
215        {
216                *end1 = 0;
217               
218                if( evil_server )
219                        req->reply_body = end1 + 2;
220                else
221                        req->reply_body = end1 + 4;
222        }
223       
224        /* Assume that a closed connection means we're finished, this indeed
225           breaks with keep-alive connections and faulty connections. */
226        req->finished = 1;
227
228cleanup:
229        if( req->ssl )
230                ssl_disconnect( req->ssl );
231        else
232                close( req->fd );
233       
234        req->func( req );
235       
236        g_free( req->request );
237        g_free( req->reply_headers );
238        g_free( req );
239}
Note: See TracBrowser for help on using the repository browser.