source: lib/http_client.c @ 12fe5ea

Last change on this file since 12fe5ea was 6b13103, checked in by dequis <dx@…>, at 2015-01-16T19:50:23Z

Replace isdigit/isalpha/.../tolower/toupper with glib variants

This fixes warnings about passing signed chars to them (apparently they
are implemented as macros that do array lookups without checks in some
platforms, yay)

Specifically:

functions=isalnum|isalpha|isdigit|isspace|isxdigit|tolower|toupper
sed -ir "s/$functions/g_ascii_&/g" /*.c

  • Property mode set to 100644
File size: 17.8 KB
RevLine 
[8a9afe4]1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
[ca8037e]4  * Copyright 2002-2013 Wilmer van der Gaast and others                *
[8a9afe4]5  \********************************************************************/
6
[52b3a99]7/* HTTP(S) module                                                       */
[8a9afe4]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;
[6f10697]22  if not, write to the Free Software Foundation, Inc., 51 Franklin St.,
23  Fifth Floor, Boston, MA  02110-1301  USA
[8a9afe4]24*/
25
26#include <string.h>
[52b3a99]27#include <stdio.h>
[8a9afe4]28
29#include "http_client.h"
[52b3a99]30#include "url.h"
[e4d6271]31#include "sock.h"
[8a9afe4]32
33
[ba9edaa]34static gboolean http_connected( gpointer data, int source, b_input_condition cond );
[486ddb5]35static gboolean http_ssl_connected( gpointer data, int returncode, void *source, b_input_condition cond );
[ba9edaa]36static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond );
[516a9c6]37static void http_free( struct http_request *req );
[8a9afe4]38
39
[516a9c6]40struct http_request *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data )
[8a9afe4]41{
42        struct http_request *req;
43        int error = 0;
44       
45        req = g_new0( struct http_request, 1 );
46       
47        if( ssl )
48        {
[a72dc2b]49                req->ssl = ssl_connect( host, port, TRUE, http_ssl_connected, req );
[8a9afe4]50                if( req->ssl == NULL )
51                        error = 1;
52        }
53        else
54        {
55                req->fd = proxy_connect( host, port, http_connected, req );
56                if( req->fd < 0 )
57                        error = 1;
58        }
59       
60        if( error )
61        {
[fb98634]62                http_free( req );
63                return NULL;
[8a9afe4]64        }
65       
[52b3a99]66        req->func = func;
67        req->data = data;
[8a9afe4]68        req->request = g_strdup( request );
69        req->request_length = strlen( request );
[7885d0f]70        req->redir_ttl = 3;
[ca8037e]71        req->content_length = -1;
[8a9afe4]72       
[3f808ca]73        if( getenv( "BITLBEE_DEBUG" ) )
74                printf( "About to send HTTP request:\n%s\n", req->request );
75       
[11ec078]76        return req;
[8a9afe4]77}
78
[516a9c6]79struct http_request *http_dorequest_url( char *url_string, http_input_function func, gpointer data )
[0790644]80{
81        url_t *url = g_new0( url_t, 1 );
82        char *request;
83        void *ret;
84       
85        if( !url_set( url, url_string ) )
86        {
87                g_free( url );
88                return NULL;
89        }
90       
91        if( url->proto != PROTO_HTTP && url->proto != PROTO_HTTPS )
92        {
93                g_free( url );
94                return NULL;
95        }
96       
97        request = g_strdup_printf( "GET %s HTTP/1.0\r\n"
98                                   "Host: %s\r\n"
[1b5ab36]99                                   "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n"
[0790644]100                                   "\r\n", url->file, url->host );
101       
102        ret = http_dorequest( url->host, url->port,
103                              url->proto == PROTO_HTTPS, request, func, data );
104       
105        g_free( url );
106        g_free( request );
[266fe2f]107        return ret;
[0790644]108}
109
[8a9afe4]110/* This one is actually pretty simple... Might get more calls if we can't write
111   the whole request at once. */
[ba9edaa]112static gboolean http_connected( gpointer data, int source, b_input_condition cond )
[8a9afe4]113{
114        struct http_request *req = data;
115        int st;
116       
117        if( source < 0 )
118                goto error;
119       
120        if( req->inpa > 0 )
[ba9edaa]121                b_event_remove( req->inpa );
[8a9afe4]122       
123        sock_make_nonblocking( req->fd );
124       
125        if( req->ssl )
126        {
127                st = ssl_write( req->ssl, req->request + req->bytes_written,
128                                req->request_length - req->bytes_written );
129                if( st < 0 )
130                {
131                        if( ssl_errno != SSL_AGAIN )
132                        {
133                                ssl_disconnect( req->ssl );
134                                goto error;
135                        }
136                }
137        }
138        else
139        {
140                st = write( source, req->request + req->bytes_written,
141                                    req->request_length - req->bytes_written );
142                if( st < 0 )
143                {
144                        if( !sockerr_again() )
145                        {
[52b3a99]146                                closesocket( req->fd );
[8a9afe4]147                                goto error;
148                        }
149                }
150        }
151       
152        if( st > 0 )
153                req->bytes_written += st;
154       
155        if( req->bytes_written < req->request_length )
[ba9edaa]156                req->inpa = b_input_add( source,
[e046390]157                                         req->ssl ? ssl_getdirection( req->ssl ) : B_EV_IO_WRITE,
[ba9edaa]158                                         http_connected, req );
[8a9afe4]159        else
[e046390]160                req->inpa = b_input_add( source, B_EV_IO_READ, http_incoming_data, req );
[8a9afe4]161       
[ba9edaa]162        return FALSE;
[8a9afe4]163       
164error:
[a72dc2b]165        if( req->status_string == NULL )
166                req->status_string = g_strdup( "Error while writing HTTP request" );
[7deb447]167       
[8a9afe4]168        req->func( req );
[fb98634]169        http_free( req );
[ba9edaa]170        return FALSE;
[8a9afe4]171}
172
[486ddb5]173static gboolean http_ssl_connected( gpointer data, int returncode, void *source, b_input_condition cond )
[8a9afe4]174{
175        struct http_request *req = data;
176       
177        if( source == NULL )
[a72dc2b]178        {
179                if( returncode != 0 )
180                {
181                        char *err = ssl_verify_strerror( returncode );
182                        req->status_string = g_strdup_printf(
183                                "Certificate verification problem 0x%x: %s",
184                                returncode, err ? err : "Unknown" );
185                        g_free( err );
186                }
[8a9afe4]187                return http_connected( data, -1, cond );
[a72dc2b]188        }
[8a9afe4]189       
190        req->fd = ssl_getfd( source );
191       
192        return http_connected( data, req->fd, cond );
193}
194
[ca8037e]195typedef enum {
196        CR_OK,
197        CR_EOF,
198        CR_ERROR,
199        CR_ABORT,
200} http_ret_t;
201
[8bd866f]202static gboolean http_handle_headers( struct http_request *req );
[ca8037e]203static http_ret_t http_process_chunked_data( struct http_request *req, const char *buffer, int len );
204static http_ret_t http_process_data( struct http_request *req, const char *buffer, int len );
[8bd866f]205
[ba9edaa]206static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond )
[8a9afe4]207{
208        struct http_request *req = data;
[5f2f728]209        char buffer[4096];
[8a9afe4]210        int st;
211       
212        if( req->inpa > 0 )
[8256ad5]213        {
[ba9edaa]214                b_event_remove( req->inpa );
[8256ad5]215                req->inpa = 0;
216        }
[8a9afe4]217       
218        if( req->ssl )
219        {
220                st = ssl_read( req->ssl, buffer, sizeof( buffer ) );
221                if( st < 0 )
222                {
223                        if( ssl_errno != SSL_AGAIN )
224                        {
[ad8b8a3]225                                /* goto cleanup; */
226                               
227                                /* YAY! We have to deal with crappy Microsoft
228                                   servers that LOVE to send invalid TLS
229                                   packets that abort connections! \o/ */
230                               
[8bd866f]231                                goto eof;
[8a9afe4]232                        }
233                }
234                else if( st == 0 )
235                {
[8bd866f]236                        goto eof;
[8a9afe4]237                }
238        }
239        else
240        {
241                st = read( req->fd, buffer, sizeof( buffer ) );
242                if( st < 0 )
243                {
244                        if( !sockerr_again() )
245                        {
[7deb447]246                                req->status_string = g_strdup( strerror( errno ) );
[8a9afe4]247                                goto cleanup;
248                        }
249                }
250                else if( st == 0 )
251                {
[8bd866f]252                        goto eof;
[8a9afe4]253                }
254        }
255       
[ca8037e]256        if( st > 0 )
[8a9afe4]257        {
[ca8037e]258                http_ret_t c;
[8bd866f]259               
[ca8037e]260                if( req->flags & HTTPC_CHUNKED )
261                        c = http_process_chunked_data( req, buffer, st );
262                else
263                        c = http_process_data( req, buffer, st );
[8bd866f]264               
[ca8037e]265                if( c == CR_EOF )
266                        goto eof;
267                else if( c == CR_ERROR || c == CR_ABORT )
268                        return FALSE;
[8a9afe4]269        }
270       
[ca8037e]271        if( req->content_length != -1 &&
272            req->body_size >= req->content_length )
273                goto eof;
274       
[8bd866f]275        if( ssl_pending( req->ssl ) )
276                return http_incoming_data( data, source, cond );
277       
[8a9afe4]278        /* There will be more! */
[ba9edaa]279        req->inpa = b_input_add( req->fd,
[e046390]280                                 req->ssl ? ssl_getdirection( req->ssl ) : B_EV_IO_READ,
[ba9edaa]281                                 http_incoming_data, req );
[8a9afe4]282       
[8bd866f]283        return FALSE;
[8a9afe4]284
[8bd866f]285eof:
[dd672e2]286        req->flags |= HTTPC_EOF;
287       
[0602496]288        /* Maybe if the webserver is overloaded, or when there's bad SSL
289           support... */
290        if( req->bytes_read == 0 )
[7deb447]291        {
292                req->status_string = g_strdup( "Empty HTTP reply" );
[0602496]293                goto cleanup;
[7deb447]294        }
[8bd866f]295
296cleanup:
[286cd48]297        /* Avoid g_source_remove warnings */
298        req->inpa = 0;
299
[8bd866f]300        if( req->ssl )
301                ssl_disconnect( req->ssl );
302        else
303                closesocket( req->fd );
304       
[ca8037e]305        if( req->body_size < req->content_length )
[8bd866f]306        {
[ca8037e]307                req->status_code = -1;
308                g_free( req->status_string );
309                req->status_string = g_strdup( "Response truncated" );
[8bd866f]310        }
311       
312        if( getenv( "BITLBEE_DEBUG" ) && req )
313                printf( "Finishing HTTP request with status: %s\n",
314                        req->status_string ? req->status_string : "NULL" );
315       
316        req->func( req );
317        http_free( req );
318        return FALSE;
319}
320
[ca8037e]321static http_ret_t http_process_chunked_data( struct http_request *req, const char *buffer, int len )
322{
323        char *chunk, *eos, *s;
324       
325        if( len < 0 )
326                return TRUE;
327       
328        if( len > 0 )
329        {
330                req->cbuf = g_realloc( req->cbuf, req->cblen + len + 1 );
331                memcpy( req->cbuf + req->cblen, buffer, len );
332                req->cblen += len;
333                req->cbuf[req->cblen] = '\0';
334        }
335       
336        /* Turns out writing a proper chunked-encoding state machine is not
[ab19567]337           that simple. :-( I've tested this one feeding it byte by byte so
338           I hope it's solid now. */
[ca8037e]339        chunk = req->cbuf;
340        eos = req->cbuf + req->cblen;
341        while( TRUE )
342        {
343                int clen = 0;
344               
345                /* Might be a \r\n from the last chunk. */
346                s = chunk;
[6b13103]347                while( g_ascii_isspace( *s ) )
[ca8037e]348                        s ++;
349                /* Chunk length. Might be incomplete. */
350                if( s < eos && sscanf( s, "%x", &clen ) != 1 )
351                        return CR_ERROR;
[6b13103]352                while( g_ascii_isxdigit( *s ) )
[ca8037e]353                        s ++;
354               
355                /* If we read anything here, it *must* be \r\n. */
356                if( strncmp( s, "\r\n", MIN( 2, eos - s ) ) != 0 )
357                        return CR_ERROR;
358                s += 2;
359               
360                if( s >= eos )
361                        break;
362               
363                /* 0-length chunk means end of response. */     
364                if( clen == 0 )
365                        return CR_EOF;
366               
[ab19567]367                /* Wait for the whole chunk to arrive. */
[ca8037e]368                if( s + clen > eos )
369                        break;
370                if( http_process_data( req, s, clen ) != CR_OK )
371                        return CR_ABORT;
372               
373                chunk = s + clen;
374        }
375       
376        if( chunk != req->cbuf )
377        {
378                req->cblen = eos - chunk;
379                s = g_memdup( chunk, req->cblen + 1 );
380                g_free( req->cbuf );
381                req->cbuf = s;
382        }
383       
384        return CR_OK;
385}
386
387static http_ret_t http_process_data( struct http_request *req, const char *buffer, int len )
388{
389        if( len <= 0 )
390                return CR_OK;
391       
392        if( !req->reply_body )
393        {
394                req->reply_headers = g_realloc( req->reply_headers, req->bytes_read + len + 1 );
395                memcpy( req->reply_headers + req->bytes_read, buffer, len );
396                req->bytes_read += len;
397                req->reply_headers[req->bytes_read] = '\0';
398               
399                if( strstr( req->reply_headers, "\r\n\r\n" ) ||
400                    strstr( req->reply_headers, "\n\n" ) )
401                {
402                        /* We've now received all headers. Look for something
403                           interesting. */
404                        if( !http_handle_headers( req ) )
405                                return CR_ABORT;
406                       
407                        /* Start parsing the body as chunked if required. */
408                        if( req->flags & HTTPC_CHUNKED )
409                                return http_process_chunked_data( req, NULL, 0 );
410                }
411        }
412        else
413        {
414                int pos = req->reply_body - req->sbuf;
415                req->sbuf = g_realloc( req->sbuf, req->sblen + len + 1 );
416                memcpy( req->sbuf + req->sblen, buffer, len );
417                req->bytes_read += len;
418                req->sblen += len;
419                req->sbuf[req->sblen] = '\0';
420                req->reply_body = req->sbuf + pos;
421                req->body_size = req->sblen - pos;
422        }
423       
424        if( ( req->flags & HTTPC_STREAMING ) && req->reply_body )
425                req->func( req );
426       
427        return CR_OK;
428}
429
[8bd866f]430/* Splits headers and body. Checks result code, in case of 300s it'll handle
431   redirects. If this returns FALSE, don't call any callbacks! */
432static gboolean http_handle_headers( struct http_request *req )
433{
[ca8037e]434        char *end1, *end2, *s;
[8bd866f]435        int evil_server = 0;
436       
[8a9afe4]437        /* Zero termination is very convenient. */
[8bd866f]438        req->reply_headers[req->bytes_read] = '\0';
[8a9afe4]439       
440        /* Find the separation between headers and body, and keep stupid
441           webservers in mind. */
442        end1 = strstr( req->reply_headers, "\r\n\r\n" );
443        end2 = strstr( req->reply_headers, "\n\n" );
444       
445        if( end2 && end2 < end1 )
446        {
[52b3a99]447                end1 = end2 + 1;
[8a9afe4]448                evil_server = 1;
449        }
[0eec386]450        else if( end1 )
[52b3a99]451        {
452                end1 += 2;
453        }
[0eec386]454        else
[8a9afe4]455        {
[7deb447]456                req->status_string = g_strdup( "Malformed HTTP reply" );
[8bd866f]457                return TRUE;
[52b3a99]458        }
459       
[ca8037e]460        *end1 = '\0';
[0eec386]461       
[bd31661]462        if( getenv( "BITLBEE_DEBUG" ) )
[3f808ca]463                printf( "HTTP response headers:\n%s\n", req->reply_headers );
[bd31661]464       
[0eec386]465        if( evil_server )
466                req->reply_body = end1 + 1;
467        else
468                req->reply_body = end1 + 2;
469       
[ca8037e]470        /* Separately allocated space for headers and body. */
471        req->sblen = req->body_size = req->reply_headers + req->bytes_read - req->reply_body;
472        req->sbuf = req->reply_body = g_memdup( req->reply_body, req->body_size + 1 );
473        req->reply_headers = g_realloc( req->reply_headers, end1 - req->reply_headers + 1 );
[0eec386]474       
[52b3a99]475        if( ( end1 = strchr( req->reply_headers, ' ' ) ) != NULL )
476        {
[8bd866f]477                if( sscanf( end1 + 1, "%hd", &req->status_code ) != 1 )
[7deb447]478                {
479                        req->status_string = g_strdup( "Can't parse status code" );
[52b3a99]480                        req->status_code = -1;
[7deb447]481                }
482                else
483                {
484                        char *eol;
485                       
486                        if( evil_server )
487                                eol = strchr( end1, '\n' );
488                        else
489                                eol = strchr( end1, '\r' );
490                       
491                        req->status_string = g_strndup( end1 + 1, eol - end1 - 1 );
492                       
493                        /* Just to be sure... */
494                        if( ( eol = strchr( req->status_string, '\r' ) ) )
495                                *eol = 0;
496                        if( ( eol = strchr( req->status_string, '\n' ) ) )
497                                *eol = 0;
498                }
[52b3a99]499        }
500        else
501        {
[7deb447]502                req->status_string = g_strdup( "Can't locate status code" );
[52b3a99]503                req->status_code = -1;
504        }
505       
[3f808ca]506        if( ( ( req->status_code >= 301 && req->status_code <= 303 ) ||
507              req->status_code == 307 ) && req->redir_ttl-- > 0 )
[52b3a99]508        {
509                char *loc, *new_request, *new_host;
510                int error = 0, new_port, new_proto;
511               
[7deb447]512                /* We might fill it again, so let's not leak any memory. */
513                g_free( req->status_string );
514                req->status_string = NULL;
515               
[52b3a99]516                loc = strstr( req->reply_headers, "\nLocation: " );
517                if( loc == NULL ) /* We can't handle this redirect... */
[7deb447]518                {
519                        req->status_string = g_strdup( "Can't locate Location: header" );
[8bd866f]520                        return TRUE;
[7deb447]521                }
[52b3a99]522               
523                loc += 11;
524                while( *loc == ' ' )
525                        loc ++;
526               
527                /* TODO/FIXME: Possibly have to handle relative redirections,
528                   and rewrite Host: headers. Not necessary for now, it's
529                   enough for passport authentication like this. */
530               
531                if( *loc == '/' )
532                {
533                        /* Just a different pathname... */
534                       
535                        /* Since we don't cache the servername, and since we
536                           don't need this yet anyway, I won't implement it. */
537                       
[ca8037e]538                        req->status_string = g_strdup( "Can't handle relative redirects" );
[7deb447]539                       
[8bd866f]540                        return TRUE;
[52b3a99]541                }
[8a9afe4]542                else
[52b3a99]543                {
544                        /* A whole URL */
545                        url_t *url;
[dd7b931]546                        char *s, *version, *headers;
[03a8f8e]547                        const char *new_method;
[52b3a99]548                       
549                        s = strstr( loc, "\r\n" );
550                        if( s == NULL )
[8bd866f]551                                return TRUE;
[52b3a99]552                       
553                        url = g_new0( url_t, 1 );
554                        *s = 0;
555                       
556                        if( !url_set( url, loc ) )
557                        {
[7deb447]558                                req->status_string = g_strdup( "Malformed redirect URL" );
[52b3a99]559                                g_free( url );
[8bd866f]560                                return TRUE;
[52b3a99]561                        }
562                       
[03a8f8e]563                        /* Find all headers and, if necessary, the POST request contents.
564                           Skip the old Host: header though. This crappy code here means
565                           anything using this http_client MUST put the Host: header at
566                           the top. */
[dff732d]567                        if( !( ( s = strstr( req->request, "\r\nHost: " ) ) &&
568                               ( s = strstr( s + strlen( "\r\nHost: " ), "\r\n" ) ) ) )
[52b3a99]569                        {
[7deb447]570                                req->status_string = g_strdup( "Error while rebuilding request string" );
[52b3a99]571                                g_free( url );
[8bd866f]572                                return TRUE;
[52b3a99]573                        }
[dd7b931]574                        headers = s;
[52b3a99]575                       
[03a8f8e]576                        /* More or less HTTP/1.0 compliant, from my reading of RFC 2616.
577                           Always perform a GET request unless we received a 301. 303 was
578                           meant for this but it's HTTP/1.1-only and we're specifically
[3f808ca]579                           speaking HTTP/1.0. ...
580                           
581                           Well except someone at identi.ca's didn't bother reading any
582                           RFCs and just return HTTP/1.1-specific status codes to HTTP/1.0
583                           requests. Fuckers. So here we are, handle 301..303,307. */
584                        if( strncmp( req->request, "GET", 3 ) == 0 )
585                                /* GETs never become POSTs. */
586                                new_method = "GET";
587                        else if( req->status_code == 302 || req->status_code == 303 )
588                                /* 302 de-facto becomes GET, 303 as specified by RFC 2616#10.3.3 */
589                                new_method = "GET";
590                        else
591                                /* 301 de-facto should stay POST, 307 specifally RFC 2616#10.3.8 */
592                                new_method = "POST";
[03a8f8e]593                       
[dd7b931]594                        if( ( version = strstr( req->request, " HTTP/" ) ) &&
595                            ( s = strstr( version, "\r\n" ) ) )
596                        {
597                                version ++;
598                                version = g_strndup( version, s - version );
599                        }
600                        else
601                                version = g_strdup( "HTTP/1.0" );
602                       
[03a8f8e]603                        /* Okay, this isn't fun! We have to rebuild the request... :-( */
[dd7b931]604                        new_request = g_strdup_printf( "%s %s %s\r\nHost: %s%s",
605                                                       new_method, url->file, version,
606                                                       url->host, headers );
[03a8f8e]607                       
[52b3a99]608                        new_host = g_strdup( url->host );
609                        new_port = url->port;
610                        new_proto = url->proto;
611                       
[03a8f8e]612                        /* If we went from POST to GET, truncate the request content. */
613                        if( new_request[0] != req->request[0] && new_request[0] == 'G' &&
614                            ( s = strstr( new_request, "\r\n\r\n" ) ) )
615                                s[4] = '\0';
616                       
[52b3a99]617                        g_free( url );
[dd7b931]618                        g_free( version );
[52b3a99]619                }
620               
621                if( req->ssl )
622                        ssl_disconnect( req->ssl );
623                else
624                        closesocket( req->fd );
625               
626                req->fd = -1;
[7deb447]627                req->ssl = NULL;
[52b3a99]628               
[bd31661]629                if( getenv( "BITLBEE_DEBUG" ) )
[3f808ca]630                        printf( "New headers for redirected HTTP request:\n%s\n", new_request );
[bd31661]631       
[52b3a99]632                if( new_proto == PROTO_HTTPS )
633                {
[a72dc2b]634                        req->ssl = ssl_connect( new_host, new_port, TRUE, http_ssl_connected, req );
[52b3a99]635                        if( req->ssl == NULL )
636                                error = 1;
637                }
638                else
639                {
640                        req->fd = proxy_connect( new_host, new_port, http_connected, req );
641                        if( req->fd < 0 )
642                                error = 1;
643                }
[2db811a]644                g_free( new_host );
[52b3a99]645               
646                if( error )
647                {
[7deb447]648                        req->status_string = g_strdup( "Connection problem during redirect" );
[52b3a99]649                        g_free( new_request );
[8bd866f]650                        return TRUE;
[52b3a99]651                }
652               
653                g_free( req->request );
654                g_free( req->reply_headers );
[ab19567]655                g_free( req->sbuf );
[52b3a99]656                req->request = new_request;
657                req->request_length = strlen( new_request );
658                req->bytes_read = req->bytes_written = req->inpa = 0;
659                req->reply_headers = req->reply_body = NULL;
[ab19567]660                req->sbuf = req->cbuf = NULL;
661                req->sblen = req->cblen = 0;
[52b3a99]662               
[ba9edaa]663                return FALSE;
[8a9afe4]664        }
[ca8037e]665
666        if( ( s = get_rfc822_header( req->reply_headers, "Content-Length", 0 ) ) &&
667            sscanf( s, "%d", &req->content_length ) != 1 )
668                req->content_length = -1;
669        g_free( s );
670       
671        if( ( s = get_rfc822_header( req->reply_headers, "Transfer-Encoding", 0 ) ) )
672        {
673                if( strcasestr( s, "chunked" ) )
674                {
675                        req->flags |= HTTPC_CHUNKED;
676                        req->cbuf = req->sbuf;
677                        req->cblen = req->sblen;
678                       
679                        req->reply_body = req->sbuf = g_strdup( "" );
680                        req->body_size = req->sblen = 0;
681                }
682                g_free( s );
683        }
[8a9afe4]684       
[8bd866f]685        return TRUE;
686}
[8a9afe4]687
[8bd866f]688void http_flush_bytes( struct http_request *req, size_t len )
689{
[1388d30]690        if( len <= 0 || len > req->body_size || !( req->flags & HTTPC_STREAMING ) )
691                return;
692       
693        req->reply_body += len;
694        req->body_size -= len;
695       
696        if( req->reply_body - req->sbuf >= 512 )
[55ccc9a0]697        {
[1388d30]698                char *new = g_memdup( req->reply_body, req->body_size + 1 );
699                g_free( req->sbuf );
700                req->reply_body = req->sbuf = new;
701                req->sblen = req->body_size;
[55ccc9a0]702        }
[fb98634]703}
704
[1388d30]705void http_close( struct http_request *req )
706{
707        if( !req )
708                return;
709       
[898c08e]710        if( req->inpa > 0 )
711                b_event_remove( req->inpa );
712       
[1388d30]713        if( req->ssl )
714                ssl_disconnect( req->ssl );
715        else
716                closesocket( req->fd );
717       
718        http_free( req );
719}
720
[516a9c6]721static void http_free( struct http_request *req )
[fb98634]722{
[8a9afe4]723        g_free( req->request );
724        g_free( req->reply_headers );
[7deb447]725        g_free( req->status_string );
[8bd866f]726        g_free( req->sbuf );
[ca8037e]727        g_free( req->cbuf );
[8a9afe4]728        g_free( req );
729}
Note: See TracBrowser for help on using the repository browser.