📄 http_get.c
字号:
/* http_get - fetch the contents of an http URL**** Originally based on a simple version by Al Globus <globus@nas.nasa.gov>.** Debugged and prettified by Jef Poskanzer <jef@mail.acme.com>. Also includes** ifdefs to handle https via OpenSSL.*/#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <signal.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>#ifdef USE_SSL#include <openssl/ssl.h>#endif/* Forwards. */static void usage();static int getURL( char* url, char* referer, char* user_agent, char* auth_token, int ncookies, char** cookies );static int getURLbyParts( int protocol, char* host, unsigned short port, char* file, char* referer, char* user_agent, char* auth_token, int ncookies, char** cookies );static int open_client_socket( char* hostname, unsigned short port );static void show_error( char* cause );static void sigcatch( int sig );static int b64_encode( unsigned char* ptr, int len, char* space, int size );/* Globals. */static char* argv0;static int verbose;static int timeout;static char* url;/* Protocol symbols. */#define PROTO_HTTP 0#ifdef USE_SSL#define PROTO_HTTPS 1#endif/* Header FSM states. */#define HDST_LINE1_PROTOCOL 0#define HDST_LINE1_WHITESPACE 1#define HDST_LINE1_STATUS 2#define HDST_BOL 10#define HDST_TEXT 11#define HDST_LF 12#define HDST_CR 13#define HDST_CRLF 14#define HDST_CRLFCR 15#define MAX_COOKIES 20intmain( int argc, char** argv ) { int argn; char* referer; char* user_agent; char* auth_token; int ncookies; char* cookies[MAX_COOKIES]; int status; argv0 = argv[0]; argn = 1; verbose = 0; timeout = 60; referer = (char*) 0; user_agent = "http_get"; auth_token = (char*) 0; ncookies = 0; while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) { if ( strcmp( argv[argn], "-v" ) == 0 ) verbose = 1; else if ( strcmp( argv[argn], "-t" ) == 0 && argn + 1 < argc ) { ++argn; timeout = atoi( argv[argn] ); } else if ( strcmp( argv[argn], "-r" ) == 0 && argn + 1 < argc ) { ++argn; referer = argv[argn]; } else if ( strcmp( argv[argn], "-u" ) == 0 && argn + 1 < argc ) { ++argn; user_agent = argv[argn]; } else if ( strcmp( argv[argn], "-a" ) == 0 && argn + 1 < argc ) { ++argn; auth_token = argv[argn]; } else if ( strcmp( argv[argn], "-c" ) == 0 && argn + 1 < argc ) { if ( ncookies >= MAX_COOKIES ) { (void) fprintf( stderr, "%s: too many cookies\n", argv0 ); exit( 1 ); } ++argn; cookies[ncookies++] = argv[argn]; } else usage(); ++argn; } if ( argn >= argc ) usage(); url = argv[argn]; ++argn; if ( argn != argc ) usage(); (void) signal( SIGALRM, sigcatch ); status = getURL( url, referer, user_agent, auth_token, ncookies, cookies ); if ( status == 200 ) exit( 0 ); else if ( status == 0 ) exit( 1 ); else exit( status ); }static voidusage() { (void) fprintf( stderr, "usage: %s [-c cookie] [-t timeout] [-r referer] [-u user-agent] [-a username:password] [-v] url\n", argv0 ); exit( 1 ); }/* URL must be of the form http://host-name[:port]/file-name */static intgetURL( char* url, char* referer, char* user_agent, char* auth_token, int ncookies, char** cookies ) { char* s; int protocol; char host[2000]; int host_len; unsigned short port; char* file = (char*) 0; char* http = "http://"; int http_len = strlen( http );#ifdef USE_SSL char* https = "https://"; int https_len = strlen( https );#endif /* USE_SSL */ int proto_len; if ( url == (char*) 0 ) { (void) fprintf( stderr, "%s: null URL\n", argv0 ); exit( 1 ); } if ( strncmp( http, url, http_len ) == 0 ) { proto_len = http_len; protocol = PROTO_HTTP; }#ifdef USE_SSL else if ( strncmp( https, url, https_len ) == 0 ) { proto_len = https_len; protocol = PROTO_HTTPS; }#endif /* USE_SSL */ else { (void) fprintf( stderr, "%s: non-http URL\n", argv0 ); exit( 1 ); } /* Get the host name. */ for ( s = url + proto_len; *s != '\0' && *s != ':' && *s != '/'; ++s ) ; host_len = s - url; host_len -= proto_len; strncpy( host, url + proto_len, host_len ); host[host_len] = '\0'; /* Get port number. */ if ( *s == ':' ) { port = (unsigned short) atoi( ++s ); while ( *s != '\0' && *s != '/' ) ++s; } else#ifdef USE_SSL if ( protocol == PROTO_HTTPS ) port = 443; else port = 80;#else port = 80;#endif /* Get the file name. */ if ( *s == '\0' ) file = "/"; else file = s; return getURLbyParts( protocol, host, port, file, referer, user_agent, auth_token, ncookies, cookies ); }static intgetURLbyParts( int protocol, char* host, unsigned short port, char* file, char* referer, char* user_agent, char* auth_token, int ncookies, char** cookies ) { int sockfd;#ifdef USE_SSL SSL_CTX* ssl_ctx; SSL* ssl;#endif char buf[20000]; int i, bytes, b, header_state, status; (void) alarm( timeout ); sockfd = open_client_socket( host, port );#ifdef USE_SSL if ( protocol == PROTO_HTTPS ) { /* Make SSL connection. */ int r; SSL_load_error_strings(); SSLeay_add_ssl_algorithms(); ssl_ctx = SSL_CTX_new( SSLv23_client_method() ); ssl = SSL_new( ssl_ctx ); SSL_set_fd( ssl, sockfd ); r = SSL_connect( ssl ); if ( r <= 0 ) { (void) fprintf( stderr, "%s: %s - SSL connection failed - %d\n", argv0, url, r ); ERR_print_errors_fp( stderr ); exit( 1 ); } }#endif /* Build request buffer, starting with the GET. */ (void) alarm( timeout ); bytes = snprintf( buf, sizeof(buf), "GET %s HTTP/1.0\r\n", file ); /* HTTP/1.1 host header - some servers want it even in HTTP/1.0. */ bytes += snprintf( &buf[bytes], sizeof(buf) - bytes, "Host: %s\r\n", host ); if ( referer != (char*) 0 ) /* Referer. */ bytes += snprintf( &buf[bytes], sizeof(buf) - bytes, "Referer: %s\r\n", referer ); /* User-agent. */ bytes += snprintf( &buf[bytes], sizeof(buf) - bytes, "User-Agent: %s\r\n", user_agent ); /* Fixed headers. */ bytes += snprintf( &buf[bytes], sizeof(buf) - bytes, "Accept: */*\r\n" ); bytes += snprintf( &buf[bytes], sizeof(buf) - bytes, "Accept-Encoding: gzip, compress\r\n" ); bytes += snprintf( &buf[bytes], sizeof(buf) - bytes, "Accept-Language: en\r\n" ); bytes += snprintf( &buf[bytes], sizeof(buf) - bytes, "Accept-Charset: iso-8859-1,*,utf-8\r\n" ); if ( auth_token != (char*) 0 ) { /* Basic Auth info. */ char token_buf[1000]; token_buf[b64_encode( auth_token, strlen( auth_token ), token_buf, sizeof(token_buf) )] = '\0'; bytes += snprintf( &buf[bytes], sizeof(buf) - bytes, "Authorization: Basic %s\r\n", token_buf ); } /* Cookies. */ for ( i = 0; i < ncookies; ++i ) bytes += snprintf( &buf[bytes], sizeof(buf) - bytes, "Cookie: %s\r\n", cookies[i] ); /* Blank line. */ bytes += snprintf( &buf[bytes], sizeof(buf) - bytes, "\r\n" ); /* Now actually send it. */#ifdef USE_SSL if ( protocol == PROTO_HTTPS ) (void) SSL_write( ssl, buf, bytes ); else (void) write( sockfd, buf, bytes );#else (void) write( sockfd, buf, bytes );#endif /* Get lines until a blank one. */ (void) alarm( timeout ); header_state = HDST_LINE1_PROTOCOL; status = 0; for (;;) {#ifdef USE_SSL if ( protocol == PROTO_HTTPS ) bytes = SSL_read( ssl, buf, sizeof(buf) ); else bytes = read( sockfd, buf, sizeof(buf) );#else bytes = read( sockfd, buf, sizeof(buf) );#endif if ( bytes <= 0 ) break; for ( b = 0; b < bytes; ++b ) { if ( verbose ) (void) write( 1, &buf[b], 1 ); switch ( header_state ) { case HDST_LINE1_PROTOCOL: switch ( buf[b] ) { case ' ': case '\t': header_state = HDST_LINE1_WHITESPACE; ; break; case '\n': header_state = HDST_LF ; break; case '\r': header_state = HDST_CR; break; } break; case HDST_LINE1_WHITESPACE: switch ( buf[b] ) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': status = buf[b] - '0'; header_state = HDST_LINE1_STATUS; break; case '\n': header_state = HDST_LF ; break; case '\r': header_state = HDST_CR; break; default: header_state = HDST_TEXT; break; } break; case HDST_LINE1_STATUS: switch ( buf[b] ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -