/***************************************************************** | | Neptune Utilities - Network 'Get' Client | | (c) 2001-2010 Gilles Boccon-Gibod | Author: Gilles Boccon-Gibod (bok@bok.net) | ****************************************************************/ /*---------------------------------------------------------------------- | includes +---------------------------------------------------------------------*/ #include "Neptune.h" #include /*---------------------------------------------------------------------- | PrintUsageAndExit +---------------------------------------------------------------------*/ static void PrintUsageAndExit(void) { fprintf(stderr, "NetGet [options] \n" "\n" " Options:\n" " --verbose : print verbose information\n" " --no-body-output : do not output the response body\n" " --http-1-1 : use HTTP 1.1\n" #if defined(NPT_CONFIG_ENABLE_TLS) " --ssl-client-cert : load client TLS certificate from (PKCS12)\n" " --ssl-client-cert-password : optional password for the client cert\n" " --ssl-accept-self-signed-certs : accept self-signed server certificates\n" " --ssl-accept-hostname-mismatch : accept server certificates that don't match\n" #endif " --show-proxy : show the proxy that will be used for the connection\n"); } /*---------------------------------------------------------------------- | main +---------------------------------------------------------------------*/ int main(int argc, char** argv) { // check command line if (argc < 2) { PrintUsageAndExit(); return 1; } // init options bool verbose = false; bool no_body_output = false; bool show_proxy = false; bool url_set = false; bool http_1_1 = false; NPT_HttpUrl url; NPT_HttpClient::Connector* connector = NULL; #if defined(NPT_CONFIG_ENABLE_TLS) NPT_TlsContext* tls_context = NULL; const char* tls_cert_filename = NULL; const char* tls_cert_password = NULL; unsigned int tls_options = 0; #endif // parse command line ++argv; const char* arg; while ((arg = *argv++)) { if (NPT_StringsEqual(arg, "--verbose")) { verbose = true; } else if (NPT_StringsEqual(arg, "--show-proxy")) { show_proxy = true; } else if (NPT_StringsEqual(arg, "--no-body-output")) { no_body_output = true; } else if (NPT_StringsEqual(arg, "--http-1-1")) { http_1_1 = true; #if defined(NPT_CONFIG_ENABLE_TLS) } else if (NPT_StringsEqual(arg, "--ssl-client-cert")) { tls_cert_filename = *argv++; if (tls_cert_filename == NULL) { fprintf(stderr, "ERROR: missing argument after --ssl-client-cert option\n"); return 1; } } else if (NPT_StringsEqual(arg, "--ssl-client-cert-password")) { tls_cert_password = *argv++; if (tls_cert_password == NULL) { fprintf(stderr, "ERROR: missing argument after --ssl-client-cert-password option\n"); return 1; } } else if (NPT_StringsEqual(arg, "--ssl-accept-self-signed-certs")) { tls_options |= NPT_HttpTlsConnector::OPTION_ACCEPT_SELF_SIGNED_CERTS; } else if (NPT_StringsEqual(arg, "--ssl-accept-hostname-mismatch")) { tls_options |= NPT_HttpTlsConnector::OPTION_ACCEPT_HOSTNAME_MISMATCH; #endif } else if (!url_set) { NPT_Result result = url.Parse(arg); if (NPT_FAILED(result)) { fprintf(stderr, "ERROR: failed to parse URL (%d:%s)\n", result, NPT_ResultText(result)); return 1; } url_set = true; } else { fprintf(stderr, "ERROR: unexpected argument '%s'\n", arg); return 1; } } if (show_proxy) { NPT_HttpProxyAddress proxy; NPT_HttpProxySelector* selector = NPT_HttpProxySelector::GetDefault(); if (selector) { NPT_Result result = selector->GetProxyForUrl(url, proxy); if (NPT_FAILED(result) && result != NPT_ERROR_HTTP_NO_PROXY) { fprintf(stderr, "ERROR: proxy selector error (%d:%s)\n", result, NPT_ResultText(result)); return 1; } } if (proxy.GetHostName().IsEmpty()) { printf("PROXY: none\n"); } else { printf("PROXY: %s:%d\n", proxy.GetHostName().GetChars(), proxy.GetPort()); } } #if defined(NPT_CONFIG_ENABLE_TLS) // load a client cert if needed if (tls_options || tls_cert_filename) { tls_context = new NPT_TlsContext(NPT_TlsContext::OPTION_VERIFY_LATER | NPT_TlsContext::OPTION_ADD_DEFAULT_TRUST_ANCHORS); if (tls_cert_filename) { NPT_DataBuffer cert; NPT_Result result = NPT_File::Load(tls_cert_filename, cert); if (NPT_FAILED(result)) { fprintf(stderr, "ERROR: failed to load client cert from file %s (%d)\n", tls_cert_filename, result); return 1; } result = tls_context->LoadKey(NPT_TLS_KEY_FORMAT_PKCS12, cert.GetData(), cert.GetDataSize(), tls_cert_password); if (NPT_FAILED(result)) { fprintf(stderr, "ERROR: failed to parse client cert (%d)\n", result); return 1; } } connector = new NPT_HttpTlsConnector(*tls_context, tls_options); } #endif // get the document NPT_HttpRequest request(url, NPT_HTTP_METHOD_GET); NPT_HttpClient client; NPT_HttpResponse* response; if (http_1_1) { request.SetProtocol(NPT_HTTP_PROTOCOL_1_1); } if (connector) { client.SetConnector(connector); } NPT_TimeStamp before_request; NPT_System::GetCurrentTimeStamp(before_request); NPT_Result result = client.SendRequest(request, response); if (NPT_FAILED(result)) { fprintf(stderr, "ERROR: SendRequest failed (%d:%s)\n", result, NPT_ResultText(result)); return 1; } NPT_TimeStamp before_body; NPT_System::GetCurrentTimeStamp(before_body); // show the request info if (verbose) { printf("#REQUEST: protocol=%s\n", request.GetProtocol().GetChars()); // show headers NPT_HttpHeaders& headers = request.GetHeaders(); NPT_List::Iterator header = headers.GetHeaders().GetFirstItem(); while (header) { printf("%s: %s\n", (const char*)(*header)->GetName(), (const char*)(*header)->GetValue()); ++header; } } // show response info if (verbose) { printf("\n#RESPONSE: protocol=%s, code=%d, reason=%s\n", response->GetProtocol().GetChars(), response->GetStatusCode(), response->GetReasonPhrase().GetChars()); // show headers NPT_HttpHeaders& headers = response->GetHeaders(); NPT_List::Iterator header = headers.GetHeaders().GetFirstItem(); while (header) { printf("%s: %s\n", (const char*)(*header)->GetName(), (const char*)(*header)->GetValue()); ++header; } } // show entity NPT_Size body_size = 0; NPT_HttpEntity* entity = response->GetEntity(); if (entity != NULL) { if (verbose) { printf("\n#ENTITY: length=%lld, type=%s, encoding=%s\n", entity->GetContentLength(), entity->GetContentType().GetChars(), entity->GetContentEncoding().GetChars()); } if (verbose) { NPT_InputStreamReference body_stream; entity->GetInputStream(body_stream); if (!body_stream.IsNull()) { NPT_LargeSize size; body_stream->GetSize(size); printf("Loading body stream (declared: %lld bytes)\n", size); } } NPT_DataBuffer body; result =entity->Load(body); if (NPT_FAILED(result)) { fprintf(stderr, "ERROR: failed to load entity (%d)\n", result); } else { body_size = body.GetDataSize(); if (verbose) printf("\n#BODY: loaded %d bytes\n", (int)body_size); // dump the body if (!no_body_output) { NPT_OutputStreamReference output; NPT_File standard_out(NPT_FILE_STANDARD_OUTPUT); standard_out.Open(NPT_FILE_OPEN_MODE_WRITE); standard_out.GetOutputStream(output); output->Write(body.GetData(), body.GetDataSize()); } } } NPT_TimeStamp after_body; NPT_System::GetCurrentTimeStamp(after_body); if (verbose) { unsigned int request_latency = (unsigned int)(before_body-before_request).ToMillis(); unsigned int body_load_time = (unsigned int)(after_body-before_body).ToMillis(); unsigned int total_load_time = (unsigned int)(after_body-before_request).ToMillis(); unsigned int body_throughput = 0; if (body_size && body_load_time) { body_throughput = (unsigned int)(((8.0 * (double)body_size)/1000.0)/((double)body_load_time/1000.0)); } unsigned int total_throughput = 0; if (body_size && total_load_time) { total_throughput = (unsigned int)(((8.0 * (double)body_size)/1000.0)/((double)total_load_time/1000.0)); } printf("\n-----------------------------------------------------------\n"); printf("TIMING:\n"); printf(" Request Latency = %d ms\n", request_latency); printf(" Body Load Time = %d ms\n", body_load_time); printf(" Total Load Time = %d ms\n", total_load_time); printf(" Body Throughput = %d kbps\n", body_throughput); printf(" Total Throughput = %d kbps\n", total_throughput); } delete response; delete connector; #if defined(NPT_CONFIG_ENABLE_TLS) delete tls_context; #endif return 0; }