- Timestamp:
- 2012-12-22T00:14:26Z (12 years ago)
- Branches:
- master
- Children:
- 7d5afa6
- Parents:
- 92d3044 (diff), 573e274 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Location:
- lib
- Files:
-
- 4 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
lib/Makefile
r92d3044 rcc6fdf8 13 13 14 14 # [SH] Program variables 15 objects = arc.o base64.o $(EVENT_HANDLER) ftutil.o http_client.o ini.o md5.o misc.o oauth.o oauth2.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o15 objects = arc.o base64.o $(EVENT_HANDLER) ftutil.o http_client.o ini.o json.o json_util.o md5.o misc.o oauth.o oauth2.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o 16 16 17 17 LFLAGS += -r -
lib/http_client.c
r92d3044 rcc6fdf8 193 193 } 194 194 195 static gboolean http_handle_headers( struct http_request *req ); 196 195 197 static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond ) 196 198 { 197 199 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; 201 202 size_t content_length; 202 203 int st; … … 218 219 packets that abort connections! \o/ */ 219 220 220 goto got_reply;221 goto eof; 221 222 } 222 223 } 223 224 else if( st == 0 ) 224 225 { 225 goto got_reply;226 goto eof; 226 227 } 227 228 } … … 239 240 else if( st == 0 ) 240 241 { 241 goto got_reply;242 } 243 } 244 245 if( st > 0 )242 goto eof; 243 } 244 } 245 246 if( st > 0 && !req->sbuf ) 246 247 { 247 248 req->reply_headers = g_realloc( req->reply_headers, req->bytes_read + st + 1 ); 248 249 memcpy( req->reply_headers + req->bytes_read, buffer, st ); 249 250 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 ); 251 295 252 296 /* There will be more! */ … … 255 299 http_incoming_data, req ); 256 300 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 303 eof: 304 req->flags |= HTTPC_EOF; 305 263 306 /* Maybe if the webserver is overloaded, or when there's bad SSL 264 307 support... */ … … 269 312 } 270 313 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 322 cleanup: 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! */ 351 static gboolean http_handle_headers( struct http_request *req ) 352 { 353 char *end1, *end2; 354 int evil_server = 0; 355 271 356 /* Zero termination is very convenient. */ 272 req->reply_headers[req->bytes_read] = 0;357 req->reply_headers[req->bytes_read] = '\0'; 273 358 274 359 /* Find the separation between headers and body, and keep stupid … … 289 374 { 290 375 req->status_string = g_strdup( "Malformed HTTP reply" ); 291 goto cleanup;376 return TRUE; 292 377 } 293 378 … … 306 391 if( ( end1 = strchr( req->reply_headers, ' ' ) ) != NULL ) 307 392 { 308 if( sscanf( end1 + 1, "% d", &req->status_code ) != 1 )393 if( sscanf( end1 + 1, "%hd", &req->status_code ) != 1 ) 309 394 { 310 395 req->status_string = g_strdup( "Can't parse status code" ); … … 349 434 { 350 435 req->status_string = g_strdup( "Can't locate Location: header" ); 351 goto cleanup;436 return TRUE; 352 437 } 353 438 … … 369 454 req->status_string = g_strdup( "Can't handle recursive redirects" ); 370 455 371 goto cleanup;456 return TRUE; 372 457 } 373 458 else … … 380 465 s = strstr( loc, "\r\n" ); 381 466 if( s == NULL ) 382 goto cleanup;467 return TRUE; 383 468 384 469 url = g_new0( url_t, 1 ); … … 389 474 req->status_string = g_strdup( "Malformed redirect URL" ); 390 475 g_free( url ); 391 goto cleanup;476 return TRUE; 392 477 } 393 478 … … 401 486 req->status_string = g_strdup( "Error while rebuilding request string" ); 402 487 g_free( url ); 403 goto cleanup;488 return TRUE; 404 489 } 405 490 … … 467 552 req->status_string = g_strdup( "Connection problem during redirect" ); 468 553 g_free( new_request ); 469 goto cleanup;554 return TRUE; 470 555 } 471 556 … … 480 565 } 481 566 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 570 void 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 588 void 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 487 596 if( req->ssl ) 488 597 ssl_disconnect( req->ssl ); … … 490 599 closesocket( req->fd ); 491 600 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 );509 601 http_free( req ); 510 return FALSE;511 602 } 512 603 … … 516 607 g_free( req->reply_headers ); 517 608 g_free( req->status_string ); 609 g_free( req->sbuf ); 518 610 g_free( req ); 519 611 } 520 -
lib/http_client.h
r92d3044 rcc6fdf8 26 26 /* http_client allows you to talk (asynchronously, again) to HTTP servers. 27 27 In the "background" it will send the whole query and wait for a complete 28 response to come back. Right now it's only used by the MSN Passport 29 authentication code, but it might be useful for other things too (for 30 example the AIM usericon patch uses this so icons can be stored on 31 webservers instead of the local filesystem). 28 response to come back. Initially written for MS Passport authentication, 29 but used for many other things now like OAuth and Twitter. 32 30 33 Didn't test this too much, but it seems to work well. Just don't look 34 at the code that handles HTTP 30x redirects. ;-) The function is 35 probably not very useful for downloading lots of data since it keeps 36 everything in a memory buffer until the download is completed (and 37 can't pass any data or whatever before then). It's very useful for 38 doing quick requests without blocking the whole program, though. */ 31 It's very useful for doing quick requests without blocking the whole 32 program. Unfortunately it doesn't support fancy stuff like HTTP keep- 33 alives. */ 39 34 40 35 #include <glib.h> … … 42 37 43 38 struct http_request; 39 40 typedef enum http_client_flags 41 { 42 HTTPC_STREAMING = 1, 43 HTTPC_EOF = 2, 44 45 /* Let's reserve 0x1000000+ for lib users. */ 46 } http_client_flags_t; 44 47 45 48 /* Your callback function should look like this: */ … … 53 56 char *request; /* The request to send to the server. */ 54 57 int request_length; /* Its size. */ 55 int status_code;/* The numeric HTTP status code. (Or -158 short status_code; /* The numeric HTTP status code. (Or -1 56 59 if something really went wrong) */ 57 60 char *status_string; /* The error text. */ … … 59 62 char *reply_body; 60 63 int body_size; /* The number of bytes in reply_body. */ 61 /* int finished; Set to non-0 if the request was completed 62 successfully. */ 63 int redir_ttl; /* You can set it to 0 if you don't want 64 short redir_ttl; /* You can set it to 0 if you don't want 64 65 http_client to follow them. */ 66 67 http_client_flags_t flags; 65 68 66 69 http_input_function func; … … 68 71 69 72 /* Please don't touch the things down here, you shouldn't need them. */ 70 71 73 void *ssl; 72 74 int fd; … … 75 77 int bytes_written; 76 78 int bytes_read; 79 80 /* Used in streaming mode. Caller should read from reply_body. */ 81 char *sbuf; 82 size_t sblen; 77 83 }; 78 84 … … 83 89 struct http_request *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ); 84 90 struct http_request *http_dorequest_url( char *url_string, http_input_function func, gpointer data ); 91 92 /* For streaming connections only; flushes len bytes at the start of the buffer. */ 93 void http_flush_bytes( struct http_request *req, size_t len ); 94 void http_close( struct http_request *req ); -
lib/oauth2.c
r92d3044 rcc6fdf8 4 4 * Simple OAuth client (consumer) implementation. * 5 5 * * 6 * Copyright 2010-201 1Wilmer van der Gaast <wilmer@gaast.net> *6 * Copyright 2010-2012 Wilmer van der Gaast <wilmer@gaast.net> * 7 7 * * 8 8 * This program is free software; you can redistribute it and/or modify * … … 26 26 #include "oauth2.h" 27 27 #include "oauth.h" 28 #include "json.h" 28 29 #include "url.h" 29 30 … … 44 45 }; 45 46 46 static char *oauth2_json_dumb_get( const char *json, const char *key );47 47 static void oauth2_access_token_done( struct http_request *req ); 48 48 … … 115 115 else if( content_type && strstr( content_type, "application/json" ) ) 116 116 { 117 atoken = oauth2_json_dumb_get( req->reply_body, "access_token" ); 118 rtoken = oauth2_json_dumb_get( req->reply_body, "refresh_token" ); 117 json_value *js = json_parse( req->reply_body ); 118 if( js && js->type == json_object ) 119 { 120 int i; 121 122 for( i = 0; i < js->u.object.length; i ++ ) 123 { 124 if( js->u.object.values[i].value->type != json_string ) 125 continue; 126 if( strcmp( js->u.object.values[i].name, "access_token" ) == 0 ) 127 atoken = g_strdup( js->u.object.values[i].value->u.string.ptr ); 128 if( strcmp( js->u.object.values[i].name, "refresh_token" ) == 0 ) 129 rtoken = g_strdup( js->u.object.values[i].value->u.string.ptr ); 130 } 131 } 132 json_value_free( js ); 119 133 } 120 134 else … … 137 151 g_free( cb_data ); 138 152 } 139 140 /* Super dumb. I absolutely refuse to use/add a complete json parser library141 (adding a new dependency to BitlBee for the first time in.. 6 years?) just142 to parse 100 bytes of data. So I have to do my own parsing because OAuth2143 dropped support for XML. (GRRR!) This is very dumb and for example won't144 work for integer values, nor will it strip/handle backslashes. */145 static char *oauth2_json_dumb_get( const char *json, const char *key )146 {147 int is_key = 0; /* 1 == reading key, 0 == reading value */148 int found_key = 0;149 150 while( json && *json )151 {152 /* Grab strings and see if they're what we're looking for. */153 if( *json == '"' || *json == '\'' )154 {155 char q = *json;156 const char *str_start;157 json ++;158 str_start = json;159 160 while( *json )161 {162 /* \' and \" are not string terminators. */163 if( *json == '\\' && json[1] == q )164 json ++;165 /* But without a \ it is. */166 else if( *json == q )167 break;168 json ++;169 }170 if( *json == '\0' )171 return NULL;172 173 if( is_key && strncmp( str_start, key, strlen( key ) ) == 0 )174 {175 found_key = 1;176 }177 else if( !is_key && found_key )178 {179 char *ret = g_memdup( str_start, json - str_start + 1 );180 ret[json-str_start] = '\0';181 return ret;182 }183 184 }185 else if( *json == '{' || *json == ',' )186 {187 found_key = 0;188 is_key = 1;189 }190 else if( *json == ':' )191 is_key = 0;192 193 json ++;194 }195 196 return NULL;197 } -
lib/ssl_gnutls.c
r92d3044 rcc6fdf8 38 38 39 39 static gboolean initialized = FALSE; 40 gnutls_certificate_credentials xcred;40 gnutls_certificate_credentials_t xcred; 41 41 42 42 #include <limits.h> … … 60 60 gboolean verify; 61 61 62 gnutls_session session;62 gnutls_session_t session; 63 63 }; 64 64 … … 134 134 conn->data = data; 135 135 conn->inpa = -1; 136 conn->hostname = hostname;136 conn->hostname = g_strdup( hostname ); 137 137 138 138 /* For now, SSL verification is globally enabled by setting the cafile … … 171 171 int verifyret = 0; 172 172 gnutls_x509_crt_t cert; 173 const char *hostname;174 175 hostname= gnutls_session_get_ptr( session );173 struct scd *conn; 174 175 conn = gnutls_session_get_ptr( session ); 176 176 177 177 gnutlsret = gnutls_certificate_verify_peers2( session, &status ); … … 211 211 return VERIFY_CERT_ERROR; 212 212 213 if( !gnutls_x509_crt_check_hostname( cert, hostname ) )213 if( !gnutls_x509_crt_check_hostname( cert, conn->hostname ) ) 214 214 { 215 215 verifyret |= VERIFY_CERT_INVALID; … … 267 267 268 268 gnutls_init( &conn->session, GNUTLS_CLIENT ); 269 if( conn->verify ) 270 gnutls_session_set_ptr( conn->session, (void *) conn->hostname ); 269 gnutls_session_set_ptr( conn->session, (void *) conn ); 271 270 #if GNUTLS_VERSION_NUMBER < 0x020c00 272 271 gnutls_transport_set_lowat( conn->session, 0 ); … … 276 275 277 276 sock_make_nonblocking( conn->fd ); 278 gnutls_transport_set_ptr( conn->session, (gnutls_transport_ptr ) GNUTLS_STUPID_CAST conn->fd );277 gnutls_transport_set_ptr( conn->session, (gnutls_transport_ptr_t) GNUTLS_STUPID_CAST conn->fd ); 279 278 280 279 return ssl_handshake( data, source, cond ); … … 402 401 if( conn->session ) 403 402 gnutls_deinit( conn->session ); 403 g_free( conn->hostname ); 404 404 g_free( conn ); 405 405 }
Note: See TracChangeset
for help on using the changeset viewer.