Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • lib/http_client.c

    r11ec078 r898c08e  
    193193}
    194194
     195static gboolean http_handle_headers( struct http_request *req );
     196
    195197static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond )
    196198{
    197199        struct http_request *req = data;
    198         int evil_server = 0;
    199         char buffer[2048];
    200         char *end1, *end2, *s;
     200        char buffer[4096];
     201        char *s;
    201202        size_t content_length;
    202203        int st;
     
    218219                                   packets that abort connections! \o/ */
    219220                               
    220                                 goto got_reply;
     221                                goto eof;
    221222                        }
    222223                }
    223224                else if( st == 0 )
    224225                {
    225                         goto got_reply;
     226                        goto eof;
    226227                }
    227228        }
     
    239240                else if( st == 0 )
    240241                {
    241                         goto got_reply;
    242                 }
    243         }
    244        
    245         if( st > 0 )
     242                        goto eof;
     243                }
     244        }
     245       
     246        if( st > 0 && !req->sbuf )
    246247        {
    247248                req->reply_headers = g_realloc( req->reply_headers, req->bytes_read + st + 1 );
    248249                memcpy( req->reply_headers + req->bytes_read, buffer, st );
    249250                req->bytes_read += st;
    250         }
     251               
     252                st = 0;
     253        }
     254       
     255        if( st >= 0 && ( req->flags & HTTPC_STREAMING ) )
     256        {
     257                if( !req->reply_body &&
     258                    ( strstr( req->reply_headers, "\r\n\r\n" ) ||
     259                      strstr( req->reply_headers, "\n\n" ) ) )
     260                {
     261                        size_t hlen;
     262                       
     263                        /* We've now received all headers, so process them once
     264                           before we start feeding back data. */
     265                        if( !http_handle_headers( req ) )
     266                                return FALSE;
     267                       
     268                        hlen = req->reply_body - req->reply_headers;
     269                       
     270                        req->sblen = req->bytes_read - hlen;
     271                        req->sbuf = g_memdup( req->reply_body, req->sblen + 1 );
     272                        req->reply_headers = g_realloc( req->reply_headers, hlen + 1 );
     273                       
     274                        req->reply_body = req->sbuf;
     275                }
     276               
     277                if( st > 0 )
     278                {
     279                        int pos = req->reply_body - req->sbuf;
     280                        req->sbuf = g_realloc( req->sbuf, req->sblen + st + 1 );
     281                        memcpy( req->sbuf + req->sblen, buffer, st );
     282                        req->bytes_read += st;
     283                        req->sblen += st;
     284                        req->sbuf[req->sblen] = '\0';
     285                        req->reply_body = req->sbuf + pos;
     286                        req->body_size = req->sblen - pos;
     287                }
     288               
     289                if( req->reply_body )
     290                        req->func( req );
     291        }
     292       
     293        if( ssl_pending( req->ssl ) )
     294                return http_incoming_data( data, source, cond );
    251295       
    252296        /* There will be more! */
     
    255299                                 http_incoming_data, req );
    256300       
    257         if( ssl_pending( req->ssl ) )
    258                 return http_incoming_data( data, source, cond );
    259         else
    260                 return FALSE;
    261 
    262 got_reply:
     301        return FALSE;
     302
     303eof:
     304        req->flags |= HTTPC_EOF;
     305       
    263306        /* Maybe if the webserver is overloaded, or when there's bad SSL
    264307           support... */
     
    269312        }
    270313       
     314        if( !( req->flags & HTTPC_STREAMING ) )
     315        {
     316                /* Returns FALSE if we were redirected, in which case we should abort
     317                   and not run any callback yet. */
     318                if( !http_handle_headers( req ) )
     319                        return FALSE;
     320        }
     321
     322cleanup:
     323        if( req->ssl )
     324                ssl_disconnect( req->ssl );
     325        else
     326                closesocket( req->fd );
     327       
     328        if( ( s = get_rfc822_header( req->reply_headers, "Content-Length", 0 ) ) &&
     329            sscanf( s, "%zd", &content_length ) == 1 )
     330        {
     331                if( content_length < req->body_size )
     332                {
     333                        req->status_code = -1;
     334                        g_free( req->status_string );
     335                        req->status_string = g_strdup( "Response truncated" );
     336                }
     337        }
     338        g_free( s );
     339       
     340        if( getenv( "BITLBEE_DEBUG" ) && req )
     341                printf( "Finishing HTTP request with status: %s\n",
     342                        req->status_string ? req->status_string : "NULL" );
     343       
     344        req->func( req );
     345        http_free( req );
     346        return FALSE;
     347}
     348
     349/* Splits headers and body. Checks result code, in case of 300s it'll handle
     350   redirects. If this returns FALSE, don't call any callbacks! */
     351static gboolean http_handle_headers( struct http_request *req )
     352{
     353        char *end1, *end2;
     354        int evil_server = 0;
     355       
    271356        /* Zero termination is very convenient. */
    272         req->reply_headers[req->bytes_read] = 0;
     357        req->reply_headers[req->bytes_read] = '\0';
    273358       
    274359        /* Find the separation between headers and body, and keep stupid
     
    289374        {
    290375                req->status_string = g_strdup( "Malformed HTTP reply" );
    291                 goto cleanup;
     376                return TRUE;
    292377        }
    293378       
     
    306391        if( ( end1 = strchr( req->reply_headers, ' ' ) ) != NULL )
    307392        {
    308                 if( sscanf( end1 + 1, "%d", &req->status_code ) != 1 )
     393                if( sscanf( end1 + 1, "%hd", &req->status_code ) != 1 )
    309394                {
    310395                        req->status_string = g_strdup( "Can't parse status code" );
     
    349434                {
    350435                        req->status_string = g_strdup( "Can't locate Location: header" );
    351                         goto cleanup;
     436                        return TRUE;
    352437                }
    353438               
     
    369454                        req->status_string = g_strdup( "Can't handle recursive redirects" );
    370455                       
    371                         goto cleanup;
     456                        return TRUE;
    372457                }
    373458                else
     
    380465                        s = strstr( loc, "\r\n" );
    381466                        if( s == NULL )
    382                                 goto cleanup;
     467                                return TRUE;
    383468                       
    384469                        url = g_new0( url_t, 1 );
     
    389474                                req->status_string = g_strdup( "Malformed redirect URL" );
    390475                                g_free( url );
    391                                 goto cleanup;
     476                                return TRUE;
    392477                        }
    393478                       
     
    401486                                req->status_string = g_strdup( "Error while rebuilding request string" );
    402487                                g_free( url );
    403                                 goto cleanup;
     488                                return TRUE;
    404489                        }
    405490                       
     
    467552                        req->status_string = g_strdup( "Connection problem during redirect" );
    468553                        g_free( new_request );
    469                         goto cleanup;
     554                        return TRUE;
    470555                }
    471556               
     
    480565        }
    481566       
    482         /* Assume that a closed connection means we're finished, this indeed
    483            breaks with keep-alive connections and faulty connections. */
    484         /* req->finished = 1; */
    485 
    486 cleanup:
     567        return TRUE;
     568}
     569
     570void http_flush_bytes( struct http_request *req, size_t len )
     571{
     572        if( len <= 0 || len > req->body_size || !( req->flags & HTTPC_STREAMING ) )
     573                return;
     574       
     575        req->reply_body += len;
     576        req->body_size -= len;
     577       
     578        if( req->reply_body - req->sbuf >= 512 )
     579        {
     580                printf( "Wasting %ld bytes, cleaning up stream buffer\n", req->reply_body - req->sbuf );
     581                char *new = g_memdup( req->reply_body, req->body_size + 1 );
     582                g_free( req->sbuf );
     583                req->reply_body = req->sbuf = new;
     584                req->sblen = req->body_size;
     585        }
     586}
     587
     588void http_close( struct http_request *req )
     589{
     590        if( !req )
     591                return;
     592       
     593        if( req->inpa > 0 )
     594                b_event_remove( req->inpa );
     595       
    487596        if( req->ssl )
    488597                ssl_disconnect( req->ssl );
     
    490599                closesocket( req->fd );
    491600       
    492         if( ( s = get_rfc822_header( req->reply_headers, "Content-Length", 0 ) ) &&
    493             sscanf( s, "%zd", &content_length ) == 1 )
    494         {
    495                 if( content_length < req->body_size )
    496                 {
    497                         req->status_code = -1;
    498                         g_free( req->status_string );
    499                         req->status_string = g_strdup( "Response truncated" );
    500                 }
    501         }
    502         g_free( s );
    503        
    504         if( getenv( "BITLBEE_DEBUG" ) && req )
    505                 printf( "Finishing HTTP request with status: %s\n",
    506                         req->status_string ? req->status_string : "NULL" );
    507        
    508         req->func( req );
    509601        http_free( req );
    510         return FALSE;
    511602}
    512603
     
    516607        g_free( req->reply_headers );
    517608        g_free( req->status_string );
     609        g_free( req->sbuf );
    518610        g_free( req );
    519611}
    520 
Note: See TracChangeset for help on using the changeset viewer.