diff options
Diffstat (limited to 'lib/http_client.c')
-rw-r--r-- | lib/http_client.c | 839 |
1 files changed, 411 insertions, 428 deletions
diff --git a/lib/http_client.c b/lib/http_client.c index 2481997a..1dc5947a 100644 --- a/lib/http_client.c +++ b/lib/http_client.c @@ -1,4 +1,4 @@ - /********************************************************************\ +/********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * * Copyright 2002-2013 Wilmer van der Gaast and others * @@ -31,165 +31,159 @@ #include "sock.h" -static gboolean http_connected( gpointer data, int source, b_input_condition cond ); -static gboolean http_ssl_connected( gpointer data, int returncode, void *source, b_input_condition cond ); -static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond ); -static void http_free( struct http_request *req ); +static gboolean http_connected(gpointer data, int source, b_input_condition cond); +static gboolean http_ssl_connected(gpointer data, int returncode, void *source, b_input_condition cond); +static gboolean http_incoming_data(gpointer data, int source, b_input_condition cond); +static void http_free(struct http_request *req); -struct http_request *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ) +struct http_request *http_dorequest(char *host, int port, int ssl, char *request, http_input_function func, + gpointer data) { struct http_request *req; int error = 0; - - req = g_new0( struct http_request, 1 ); - - if( ssl ) - { - req->ssl = ssl_connect( host, port, TRUE, http_ssl_connected, req ); - if( req->ssl == NULL ) + + req = g_new0(struct http_request, 1); + + if (ssl) { + req->ssl = ssl_connect(host, port, TRUE, http_ssl_connected, req); + if (req->ssl == NULL) { error = 1; - } - else - { - req->fd = proxy_connect( host, port, http_connected, req ); - if( req->fd < 0 ) + } + } else { + req->fd = proxy_connect(host, port, http_connected, req); + if (req->fd < 0) { error = 1; + } } - - if( error ) - { - http_free( req ); + + if (error) { + http_free(req); return NULL; } - + req->func = func; req->data = data; - req->request = g_strdup( request ); - req->request_length = strlen( request ); + req->request = g_strdup(request); + req->request_length = strlen(request); req->redir_ttl = 3; req->content_length = -1; - - if( getenv( "BITLBEE_DEBUG" ) ) - printf( "About to send HTTP request:\n%s\n", req->request ); - + + if (getenv("BITLBEE_DEBUG")) { + printf("About to send HTTP request:\n%s\n", req->request); + } + return req; } -struct http_request *http_dorequest_url( char *url_string, http_input_function func, gpointer data ) +struct http_request *http_dorequest_url(char *url_string, http_input_function func, gpointer data) { - url_t *url = g_new0( url_t, 1 ); + url_t *url = g_new0(url_t, 1); char *request; void *ret; - - if( !url_set( url, url_string ) ) - { - g_free( url ); + + if (!url_set(url, url_string)) { + g_free(url); return NULL; } - - if( url->proto != PROTO_HTTP && url->proto != PROTO_HTTPS ) - { - g_free( url ); + + 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 ); + + 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 +/* This one is actually pretty simple... Might get more calls if we can't write the whole request at once. */ -static gboolean http_connected( gpointer data, int source, b_input_condition cond ) +static gboolean http_connected(gpointer data, int source, b_input_condition cond) { struct http_request *req = data; int st; - - if( source < 0 ) + + if (source < 0) { goto error; - - if( req->inpa > 0 ) - b_event_remove( req->inpa ); - - sock_make_nonblocking( req->fd ); - - if( req->ssl ) - { - st = ssl_write( req->ssl, req->request + req->bytes_written, - req->request_length - req->bytes_written ); - if( st < 0 ) - { - if( ssl_errno != SSL_AGAIN ) - { - ssl_disconnect( req->ssl ); + } + + if (req->inpa > 0) { + b_event_remove(req->inpa); + } + + sock_make_nonblocking(req->fd); + + if (req->ssl) { + st = ssl_write(req->ssl, req->request + req->bytes_written, + req->request_length - req->bytes_written); + if (st < 0) { + if (ssl_errno != SSL_AGAIN) { + ssl_disconnect(req->ssl); goto error; } } - } - else - { - st = write( source, req->request + req->bytes_written, - req->request_length - req->bytes_written ); - if( st < 0 ) - { - if( !sockerr_again() ) - { - closesocket( req->fd ); + } else { + st = write(source, req->request + req->bytes_written, + req->request_length - req->bytes_written); + if (st < 0) { + if (!sockerr_again()) { + closesocket(req->fd); goto error; } } } - - if( st > 0 ) + + if (st > 0) { req->bytes_written += st; - - if( req->bytes_written < req->request_length ) - req->inpa = b_input_add( source, - req->ssl ? ssl_getdirection( req->ssl ) : B_EV_IO_WRITE, - http_connected, req ); - else - req->inpa = b_input_add( source, B_EV_IO_READ, http_incoming_data, req ); - + } + + if (req->bytes_written < req->request_length) { + req->inpa = b_input_add(source, + req->ssl ? ssl_getdirection(req->ssl) : B_EV_IO_WRITE, + http_connected, req); + } else { + req->inpa = b_input_add(source, B_EV_IO_READ, http_incoming_data, req); + } + return FALSE; - + error: - if( req->status_string == NULL ) - req->status_string = g_strdup( "Error while writing HTTP request" ); - - req->func( req ); - http_free( req ); + if (req->status_string == NULL) { + req->status_string = g_strdup("Error while writing HTTP request"); + } + + req->func(req); + http_free(req); return FALSE; } -static gboolean http_ssl_connected( gpointer data, int returncode, void *source, b_input_condition cond ) +static gboolean http_ssl_connected(gpointer data, int returncode, void *source, b_input_condition cond) { struct http_request *req = data; - - if( source == NULL ) - { - if( returncode != 0 ) - { - char *err = ssl_verify_strerror( returncode ); + + if (source == NULL) { + if (returncode != 0) { + char *err = ssl_verify_strerror(returncode); req->status_string = g_strdup_printf( - "Certificate verification problem 0x%x: %s", - returncode, err ? err : "Unknown" ); - g_free( err ); + "Certificate verification problem 0x%x: %s", + returncode, err ? err : "Unknown"); + g_free(err); } - return http_connected( data, -1, cond ); + return http_connected(data, -1, cond); } - - req->fd = ssl_getfd( source ); - - return http_connected( data, req->fd, cond ); + + req->fd = ssl_getfd(source); + + return http_connected(data, req->fd, cond); } typedef enum { @@ -199,97 +193,87 @@ typedef enum { CR_ABORT, } http_ret_t; -static gboolean http_handle_headers( struct http_request *req ); -static http_ret_t http_process_chunked_data( struct http_request *req, const char *buffer, int len ); -static http_ret_t http_process_data( struct http_request *req, const char *buffer, int len ); +static gboolean http_handle_headers(struct http_request *req); +static http_ret_t http_process_chunked_data(struct http_request *req, const char *buffer, int len); +static http_ret_t http_process_data(struct http_request *req, const char *buffer, int len); -static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond ) +static gboolean http_incoming_data(gpointer data, int source, b_input_condition cond) { struct http_request *req = data; char buffer[4096]; int st; - - if( req->inpa > 0 ) - { - b_event_remove( req->inpa ); + + if (req->inpa > 0) { + b_event_remove(req->inpa); req->inpa = 0; } - - if( req->ssl ) - { - st = ssl_read( req->ssl, buffer, sizeof( buffer ) ); - if( st < 0 ) - { - if( ssl_errno != SSL_AGAIN ) - { + + if (req->ssl) { + st = ssl_read(req->ssl, buffer, sizeof(buffer)); + if (st < 0) { + if (ssl_errno != SSL_AGAIN) { /* goto cleanup; */ - + /* YAY! We have to deal with crappy Microsoft servers that LOVE to send invalid TLS packets that abort connections! \o/ */ - + goto eof; } - } - else if( st == 0 ) - { + } else if (st == 0) { goto eof; } - } - else - { - st = read( req->fd, buffer, sizeof( buffer ) ); - if( st < 0 ) - { - if( !sockerr_again() ) - { - req->status_string = g_strdup( strerror( errno ) ); + } else { + st = read(req->fd, buffer, sizeof(buffer)); + if (st < 0) { + if (!sockerr_again()) { + req->status_string = g_strdup(strerror(errno)); goto cleanup; } - } - else if( st == 0 ) - { + } else if (st == 0) { goto eof; } } - - if( st > 0 ) - { + + if (st > 0) { http_ret_t c; - - if( req->flags & HTTPC_CHUNKED ) - c = http_process_chunked_data( req, buffer, st ); - else - c = http_process_data( req, buffer, st ); - - if( c == CR_EOF ) + + if (req->flags & HTTPC_CHUNKED) { + c = http_process_chunked_data(req, buffer, st); + } else { + c = http_process_data(req, buffer, st); + } + + if (c == CR_EOF) { goto eof; - else if( c == CR_ERROR || c == CR_ABORT ) + } else if (c == CR_ERROR || c == CR_ABORT) { return FALSE; + } } - - if( req->content_length != -1 && - req->body_size >= req->content_length ) + + if (req->content_length != -1 && + req->body_size >= req->content_length) { goto eof; - - if( ssl_pending( req->ssl ) ) - return http_incoming_data( data, source, cond ); - + } + + if (ssl_pending(req->ssl)) { + return http_incoming_data(data, source, cond); + } + /* There will be more! */ - req->inpa = b_input_add( req->fd, - req->ssl ? ssl_getdirection( req->ssl ) : B_EV_IO_READ, - http_incoming_data, req ); - + req->inpa = b_input_add(req->fd, + req->ssl ? ssl_getdirection(req->ssl) : B_EV_IO_READ, + http_incoming_data, req); + return FALSE; eof: req->flags |= HTTPC_EOF; - + /* 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" ); + if (req->bytes_read == 0) { + req->status_string = g_strdup("Empty HTTP reply"); goto cleanup; } @@ -297,433 +281,432 @@ cleanup: /* Avoid g_source_remove warnings */ req->inpa = 0; - if( req->ssl ) - ssl_disconnect( req->ssl ); - else - closesocket( req->fd ); - - if( req->body_size < req->content_length ) - { + if (req->ssl) { + ssl_disconnect(req->ssl); + } else { + closesocket(req->fd); + } + + if (req->body_size < req->content_length) { req->status_code = -1; - g_free( req->status_string ); - req->status_string = g_strdup( "Response truncated" ); - } - - if( getenv( "BITLBEE_DEBUG" ) && req ) - printf( "Finishing HTTP request with status: %s\n", - req->status_string ? req->status_string : "NULL" ); - - req->func( req ); - http_free( req ); + g_free(req->status_string); + req->status_string = g_strdup("Response truncated"); + } + + if (getenv("BITLBEE_DEBUG") && req) { + printf("Finishing HTTP request with status: %s\n", + req->status_string ? req->status_string : "NULL"); + } + + req->func(req); + http_free(req); return FALSE; } -static http_ret_t http_process_chunked_data( struct http_request *req, const char *buffer, int len ) +static http_ret_t http_process_chunked_data(struct http_request *req, const char *buffer, int len) { char *chunk, *eos, *s; - - if( len < 0 ) + + if (len < 0) { return TRUE; - - if( len > 0 ) - { - req->cbuf = g_realloc( req->cbuf, req->cblen + len + 1 ); - memcpy( req->cbuf + req->cblen, buffer, len ); + } + + if (len > 0) { + req->cbuf = g_realloc(req->cbuf, req->cblen + len + 1); + memcpy(req->cbuf + req->cblen, buffer, len); req->cblen += len; req->cbuf[req->cblen] = '\0'; } - + /* Turns out writing a proper chunked-encoding state machine is not that simple. :-( I've tested this one feeding it byte by byte so I hope it's solid now. */ chunk = req->cbuf; eos = req->cbuf + req->cblen; - while( TRUE ) - { + while (TRUE) { int clen = 0; - + /* Might be a \r\n from the last chunk. */ s = chunk; - while( g_ascii_isspace( *s ) ) - s ++; + while (g_ascii_isspace(*s)) { + s++; + } /* Chunk length. Might be incomplete. */ - if( s < eos && sscanf( s, "%x", &clen ) != 1 ) + if (s < eos && sscanf(s, "%x", &clen) != 1) { return CR_ERROR; - while( g_ascii_isxdigit( *s ) ) - s ++; - + } + while (g_ascii_isxdigit(*s)) { + s++; + } + /* If we read anything here, it *must* be \r\n. */ - if( strncmp( s, "\r\n", MIN( 2, eos - s ) ) != 0 ) + if (strncmp(s, "\r\n", MIN(2, eos - s)) != 0) { return CR_ERROR; + } s += 2; - - if( s >= eos ) + + if (s >= eos) { break; - - /* 0-length chunk means end of response. */ - if( clen == 0 ) + } + + /* 0-length chunk means end of response. */ + if (clen == 0) { return CR_EOF; - + } + /* Wait for the whole chunk to arrive. */ - if( s + clen > eos ) + if (s + clen > eos) { break; - if( http_process_data( req, s, clen ) != CR_OK ) + } + if (http_process_data(req, s, clen) != CR_OK) { return CR_ABORT; - + } + chunk = s + clen; } - - if( chunk != req->cbuf ) - { + + if (chunk != req->cbuf) { req->cblen = eos - chunk; - s = g_memdup( chunk, req->cblen + 1 ); - g_free( req->cbuf ); + s = g_memdup(chunk, req->cblen + 1); + g_free(req->cbuf); req->cbuf = s; } - + return CR_OK; } -static http_ret_t http_process_data( struct http_request *req, const char *buffer, int len ) +static http_ret_t http_process_data(struct http_request *req, const char *buffer, int len) { - if( len <= 0 ) + if (len <= 0) { return CR_OK; - - if( !req->reply_body ) - { - req->reply_headers = g_realloc( req->reply_headers, req->bytes_read + len + 1 ); - memcpy( req->reply_headers + req->bytes_read, buffer, len ); + } + + if (!req->reply_body) { + req->reply_headers = g_realloc(req->reply_headers, req->bytes_read + len + 1); + memcpy(req->reply_headers + req->bytes_read, buffer, len); req->bytes_read += len; req->reply_headers[req->bytes_read] = '\0'; - - if( strstr( req->reply_headers, "\r\n\r\n" ) || - strstr( req->reply_headers, "\n\n" ) ) - { + + if (strstr(req->reply_headers, "\r\n\r\n") || + strstr(req->reply_headers, "\n\n")) { /* We've now received all headers. Look for something interesting. */ - if( !http_handle_headers( req ) ) + if (!http_handle_headers(req)) { return CR_ABORT; - + } + /* Start parsing the body as chunked if required. */ - if( req->flags & HTTPC_CHUNKED ) - return http_process_chunked_data( req, NULL, 0 ); + if (req->flags & HTTPC_CHUNKED) { + return http_process_chunked_data(req, NULL, 0); + } } - } - else - { + } else { int pos = req->reply_body - req->sbuf; - req->sbuf = g_realloc( req->sbuf, req->sblen + len + 1 ); - memcpy( req->sbuf + req->sblen, buffer, len ); + req->sbuf = g_realloc(req->sbuf, req->sblen + len + 1); + memcpy(req->sbuf + req->sblen, buffer, len); req->bytes_read += len; req->sblen += len; req->sbuf[req->sblen] = '\0'; req->reply_body = req->sbuf + pos; req->body_size = req->sblen - pos; } - - if( ( req->flags & HTTPC_STREAMING ) && req->reply_body ) - req->func( req ); - + + if ((req->flags & HTTPC_STREAMING) && req->reply_body) { + req->func(req); + } + return CR_OK; } /* Splits headers and body. Checks result code, in case of 300s it'll handle redirects. If this returns FALSE, don't call any callbacks! */ -static gboolean http_handle_headers( struct http_request *req ) +static gboolean http_handle_headers(struct http_request *req) { char *end1, *end2, *s; int evil_server = 0; - + /* Zero termination is very convenient. */ req->reply_headers[req->bytes_read] = '\0'; - + /* Find the separation between headers and body, and keep stupid webservers in mind. */ - end1 = strstr( req->reply_headers, "\r\n\r\n" ); - end2 = strstr( req->reply_headers, "\n\n" ); - - if( end2 && end2 < end1 ) - { + end1 = strstr(req->reply_headers, "\r\n\r\n"); + end2 = strstr(req->reply_headers, "\n\n"); + + if (end2 && end2 < end1) { end1 = end2 + 1; evil_server = 1; - } - else if( end1 ) - { + } else if (end1) { end1 += 2; - } - else - { - req->status_string = g_strdup( "Malformed HTTP reply" ); + } else { + req->status_string = g_strdup("Malformed HTTP reply"); return TRUE; } - + *end1 = '\0'; - - if( getenv( "BITLBEE_DEBUG" ) ) - printf( "HTTP response headers:\n%s\n", req->reply_headers ); - - if( evil_server ) + + if (getenv("BITLBEE_DEBUG")) { + printf("HTTP response headers:\n%s\n", req->reply_headers); + } + + if (evil_server) { req->reply_body = end1 + 1; - else + } else { req->reply_body = end1 + 2; - + } + /* Separately allocated space for headers and body. */ req->sblen = req->body_size = req->reply_headers + req->bytes_read - req->reply_body; - req->sbuf = req->reply_body = g_memdup( req->reply_body, req->body_size + 1 ); - req->reply_headers = g_realloc( req->reply_headers, end1 - req->reply_headers + 1 ); - - if( ( end1 = strchr( req->reply_headers, ' ' ) ) != NULL ) - { - if( sscanf( end1 + 1, "%hd", &req->status_code ) != 1 ) - { - req->status_string = g_strdup( "Can't parse status code" ); + req->sbuf = req->reply_body = g_memdup(req->reply_body, req->body_size + 1); + req->reply_headers = g_realloc(req->reply_headers, end1 - req->reply_headers + 1); + + if ((end1 = strchr(req->reply_headers, ' ')) != NULL) { + if (sscanf(end1 + 1, "%hd", &req->status_code) != 1) { + req->status_string = g_strdup("Can't parse status code"); req->status_code = -1; - } - else - { + } 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 ); - + + 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' ) ) ) + if ((eol = strchr(req->status_string, '\r'))) { *eol = 0; - if( ( eol = strchr( req->status_string, '\n' ) ) ) + } + if ((eol = strchr(req->status_string, '\n'))) { *eol = 0; + } } - } - else - { - req->status_string = g_strdup( "Can't locate status code" ); + } else { + req->status_string = g_strdup("Can't locate status code"); req->status_code = -1; } - - if( ( ( req->status_code >= 301 && req->status_code <= 303 ) || - req->status_code == 307 ) && req->redir_ttl-- > 0 ) - { + + if (((req->status_code >= 301 && req->status_code <= 303) || + req->status_code == 307) && req->redir_ttl-- > 0) { 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 ); + 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" ); + + 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"); return TRUE; } - + loc += 11; - while( *loc == ' ' ) - loc ++; - + while (*loc == ' ') { + loc++; + } + /* TODO/FIXME: Possibly have to handle relative redirections, and rewrite Host: headers. Not necessary for now, it's enough for passport authentication like this. */ - - if( *loc == '/' ) - { + + if (*loc == '/') { /* Just a different pathname... */ - + /* 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 relative redirects" ); - + + req->status_string = g_strdup("Can't handle relative redirects"); + return TRUE; - } - else - { + } else { /* A whole URL */ url_t *url; char *s, *version, *headers; const char *new_method; - - s = strstr( loc, "\r\n" ); - if( s == NULL ) + + s = strstr(loc, "\r\n"); + if (s == NULL) { return TRUE; - - url = g_new0( url_t, 1 ); + } + + url = g_new0(url_t, 1); *s = 0; - - if( !url_set( url, loc ) ) - { - req->status_string = g_strdup( "Malformed redirect URL" ); - g_free( url ); + + if (!url_set(url, loc)) { + req->status_string = g_strdup("Malformed redirect URL"); + g_free(url); return TRUE; } - + /* Find all headers and, if necessary, the POST request contents. Skip the old Host: header though. This crappy code here means anything using this http_client MUST put the Host: header at the top. */ - if( !( ( s = strstr( req->request, "\r\nHost: " ) ) && - ( s = strstr( s + strlen( "\r\nHost: " ), "\r\n" ) ) ) ) - { - req->status_string = g_strdup( "Error while rebuilding request string" ); - g_free( url ); + if (!((s = strstr(req->request, "\r\nHost: ")) && + (s = strstr(s + strlen("\r\nHost: "), "\r\n")))) { + req->status_string = g_strdup("Error while rebuilding request string"); + g_free(url); return TRUE; } headers = s; - + /* More or less HTTP/1.0 compliant, from my reading of RFC 2616. Always perform a GET request unless we received a 301. 303 was meant for this but it's HTTP/1.1-only and we're specifically speaking HTTP/1.0. ... - + Well except someone at identi.ca's didn't bother reading any RFCs and just return HTTP/1.1-specific status codes to HTTP/1.0 requests. Fuckers. So here we are, handle 301..303,307. */ - if( strncmp( req->request, "GET", 3 ) == 0 ) + if (strncmp(req->request, "GET", 3) == 0) { /* GETs never become POSTs. */ new_method = "GET"; - else if( req->status_code == 302 || req->status_code == 303 ) + } else if (req->status_code == 302 || req->status_code == 303) { /* 302 de-facto becomes GET, 303 as specified by RFC 2616#10.3.3 */ new_method = "GET"; - else + } else { /* 301 de-facto should stay POST, 307 specifally RFC 2616#10.3.8 */ new_method = "POST"; - - if( ( version = strstr( req->request, " HTTP/" ) ) && - ( s = strstr( version, "\r\n" ) ) ) - { - version ++; - version = g_strndup( version, s - version ); } - else - version = g_strdup( "HTTP/1.0" ); - + + if ((version = strstr(req->request, " HTTP/")) && + (s = strstr(version, "\r\n"))) { + version++; + version = g_strndup(version, s - version); + } else { + version = g_strdup("HTTP/1.0"); + } + /* Okay, this isn't fun! We have to rebuild the request... :-( */ - new_request = g_strdup_printf( "%s %s %s\r\nHost: %s%s", - new_method, url->file, version, - url->host, headers ); - - new_host = g_strdup( url->host ); + new_request = g_strdup_printf("%s %s %s\r\nHost: %s%s", + new_method, url->file, version, + url->host, headers); + + new_host = g_strdup(url->host); new_port = url->port; new_proto = url->proto; - + /* If we went from POST to GET, truncate the request content. */ - if( new_request[0] != req->request[0] && new_request[0] == 'G' && - ( s = strstr( new_request, "\r\n\r\n" ) ) ) + if (new_request[0] != req->request[0] && new_request[0] == 'G' && + (s = strstr(new_request, "\r\n\r\n"))) { s[4] = '\0'; - - g_free( url ); - g_free( version ); + } + + g_free(url); + g_free(version); + } + + if (req->ssl) { + ssl_disconnect(req->ssl); + } else { + closesocket(req->fd); } - - if( req->ssl ) - ssl_disconnect( req->ssl ); - else - closesocket( req->fd ); - + req->fd = -1; req->ssl = NULL; - - if( getenv( "BITLBEE_DEBUG" ) ) - printf( "New headers for redirected HTTP request:\n%s\n", new_request ); - - if( new_proto == PROTO_HTTPS ) - { - req->ssl = ssl_connect( new_host, new_port, TRUE, http_ssl_connected, req ); - if( req->ssl == NULL ) - error = 1; + + if (getenv("BITLBEE_DEBUG")) { + printf("New headers for redirected HTTP request:\n%s\n", new_request); } - else - { - req->fd = proxy_connect( new_host, new_port, http_connected, req ); - if( req->fd < 0 ) + + if (new_proto == PROTO_HTTPS) { + req->ssl = ssl_connect(new_host, new_port, TRUE, http_ssl_connected, req); + if (req->ssl == NULL) { error = 1; + } + } else { + req->fd = proxy_connect(new_host, new_port, http_connected, req); + if (req->fd < 0) { + error = 1; + } } - g_free( new_host ); - - if( error ) - { - req->status_string = g_strdup( "Connection problem during redirect" ); - g_free( new_request ); + g_free(new_host); + + if (error) { + req->status_string = g_strdup("Connection problem during redirect"); + g_free(new_request); return TRUE; } - - g_free( req->request ); - g_free( req->reply_headers ); - g_free( req->sbuf ); + + g_free(req->request); + g_free(req->reply_headers); + g_free(req->sbuf); req->request = new_request; - req->request_length = strlen( new_request ); + req->request_length = strlen(new_request); req->bytes_read = req->bytes_written = req->inpa = 0; req->reply_headers = req->reply_body = NULL; req->sbuf = req->cbuf = NULL; req->sblen = req->cblen = 0; - + return FALSE; } - if( ( s = get_rfc822_header( req->reply_headers, "Content-Length", 0 ) ) && - sscanf( s, "%d", &req->content_length ) != 1 ) + if ((s = get_rfc822_header(req->reply_headers, "Content-Length", 0)) && + sscanf(s, "%d", &req->content_length) != 1) { req->content_length = -1; - g_free( s ); - - if( ( s = get_rfc822_header( req->reply_headers, "Transfer-Encoding", 0 ) ) ) - { - if( strcasestr( s, "chunked" ) ) - { + } + g_free(s); + + if ((s = get_rfc822_header(req->reply_headers, "Transfer-Encoding", 0))) { + if (strcasestr(s, "chunked")) { req->flags |= HTTPC_CHUNKED; req->cbuf = req->sbuf; req->cblen = req->sblen; - - req->reply_body = req->sbuf = g_strdup( "" ); + + req->reply_body = req->sbuf = g_strdup(""); req->body_size = req->sblen = 0; } - g_free( s ); + g_free(s); } - + return TRUE; } -void http_flush_bytes( struct http_request *req, size_t len ) +void http_flush_bytes(struct http_request *req, size_t len) { - if( len <= 0 || len > req->body_size || !( req->flags & HTTPC_STREAMING ) ) + if (len <= 0 || len > req->body_size || !(req->flags & HTTPC_STREAMING)) { return; - + } + req->reply_body += len; req->body_size -= len; - - if( req->reply_body - req->sbuf >= 512 ) - { - char *new = g_memdup( req->reply_body, req->body_size + 1 ); - g_free( req->sbuf ); + + if (req->reply_body - req->sbuf >= 512) { + char *new = g_memdup(req->reply_body, req->body_size + 1); + g_free(req->sbuf); req->reply_body = req->sbuf = new; req->sblen = req->body_size; } } -void http_close( struct http_request *req ) +void http_close(struct http_request *req) { - if( !req ) + if (!req) { return; - - if( req->inpa > 0 ) - b_event_remove( req->inpa ); - - if( req->ssl ) - ssl_disconnect( req->ssl ); - else - closesocket( req->fd ); - - http_free( req ); + } + + if (req->inpa > 0) { + b_event_remove(req->inpa); + } + + if (req->ssl) { + ssl_disconnect(req->ssl); + } else { + closesocket(req->fd); + } + + http_free(req); } -static void http_free( struct http_request *req ) +static void http_free(struct http_request *req) { - g_free( req->request ); - g_free( req->reply_headers ); - g_free( req->status_string ); - g_free( req->sbuf ); - g_free( req->cbuf ); - g_free( req ); + g_free(req->request); + g_free(req->reply_headers); + g_free(req->status_string); + g_free(req->sbuf); + g_free(req->cbuf); + g_free(req); } |