Path: blob/main/external/curl/tests/http/clients/upload-pausing.c
2066 views
/***************************************************************************1* _ _ ____ _2* Project ___| | | | _ \| |3* / __| | | | |_) | |4* | (__| |_| | _ <| |___5* \___|\___/|_| \_\_____|6*7* Copyright (C) Daniel Stenberg, <[email protected]>, et al.8*9* This software is licensed as described in the file COPYING, which10* you should have received as part of this distribution. The terms11* are also available at https://curl.se/docs/copyright.html.12*13* You may opt to use, copy, modify, merge, publish, distribute and/or sell14* copies of the Software, and permit persons to whom the Software is15* furnished to do so, under the terms of the COPYING file.16*17* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY18* KIND, either express or implied.19*20* SPDX-License-Identifier: curl21*22***************************************************************************/23/* <DESC>24* upload pausing25* </DESC>26*/27/* This is based on the PoC client of issue #1176928*/29#include <curl/curl.h>3031#include <stdio.h>32#include <string.h>33#include <stdlib.h>3435#ifndef _MSC_VER36/* somewhat Unix-specific */37#include <unistd.h> /* getopt() */38#endif3940#ifndef _MSC_VER41static void log_line_start(FILE *log, const char *idsbuf, curl_infotype type)42{43/*44* This is the trace look that is similar to what libcurl makes on its45* own.46*/47static const char * const s_infotype[] = {48"* ", "< ", "> ", "{ ", "} ", "{ ", "} "49};50if(idsbuf && *idsbuf)51fprintf(log, "%s%s", idsbuf, s_infotype[type]);52else53fputs(s_infotype[type], log);54}5556#define TRC_IDS_FORMAT_IDS_1 "[%" CURL_FORMAT_CURL_OFF_T "-x] "57#define TRC_IDS_FORMAT_IDS_2 "[%" CURL_FORMAT_CURL_OFF_T "-%" \58CURL_FORMAT_CURL_OFF_T "] "59/*60** callback for CURLOPT_DEBUGFUNCTION61*/62static int debug_cb(CURL *handle, curl_infotype type,63char *data, size_t size,64void *userdata)65{66FILE *output = stderr;67static int newl = 0;68static int traced_data = 0;69char idsbuf[60];70curl_off_t xfer_id, conn_id;7172(void)handle; /* not used */73(void)userdata;7475if(!curl_easy_getinfo(handle, CURLINFO_XFER_ID, &xfer_id) && xfer_id >= 0) {76if(!curl_easy_getinfo(handle, CURLINFO_CONN_ID, &conn_id) &&77conn_id >= 0) {78curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_2, xfer_id,79conn_id);80}81else {82curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_1, xfer_id);83}84}85else86idsbuf[0] = 0;8788switch(type) {89case CURLINFO_HEADER_OUT:90if(size > 0) {91size_t st = 0;92size_t i;93for(i = 0; i < size - 1; i++) {94if(data[i] == '\n') { /* LF */95if(!newl) {96log_line_start(output, idsbuf, type);97}98(void)fwrite(data + st, i - st + 1, 1, output);99st = i + 1;100newl = 0;101}102}103if(!newl)104log_line_start(output, idsbuf, type);105(void)fwrite(data + st, i - st + 1, 1, output);106}107newl = (size && (data[size - 1] != '\n')) ? 1 : 0;108traced_data = 0;109break;110case CURLINFO_TEXT:111case CURLINFO_HEADER_IN:112if(!newl)113log_line_start(output, idsbuf, type);114(void)fwrite(data, size, 1, output);115newl = (size && (data[size - 1] != '\n')) ? 1 : 0;116traced_data = 0;117break;118case CURLINFO_DATA_OUT:119case CURLINFO_DATA_IN:120case CURLINFO_SSL_DATA_IN:121case CURLINFO_SSL_DATA_OUT:122if(!traced_data) {123if(!newl)124log_line_start(output, idsbuf, type);125fprintf(output, "[%ld bytes data]\n", (long)size);126newl = 0;127traced_data = 1;128}129break;130default: /* nada */131newl = 0;132traced_data = 1;133break;134}135136return 0;137}138139#define PAUSE_READ_AFTER 1140static size_t total_read = 0;141142static size_t read_callback(char *ptr, size_t size, size_t nmemb,143void *userdata)144{145(void)size;146(void)nmemb;147(void)userdata;148if(total_read >= PAUSE_READ_AFTER) {149fprintf(stderr, "read_callback, return PAUSE\n");150return CURL_READFUNC_PAUSE;151}152else {153ptr[0] = '\n';154++total_read;155fprintf(stderr, "read_callback, return 1 byte\n");156return 1;157}158}159160static int progress_callback(void *clientp,161curl_off_t dltotal,162curl_off_t dlnow,163curl_off_t ultotal,164curl_off_t ulnow)165{166(void)dltotal;167(void)dlnow;168(void)ultotal;169(void)ulnow;170(void)clientp;171#if 0172/* Used to unpause on progress, but keeping for now. */173{174CURL *curl = (CURL *)clientp;175curl_easy_pause(curl, CURLPAUSE_CONT);176/* curl_easy_pause(curl, CURLPAUSE_RECV_CONT); */177}178#endif179return 0;180}181182static void usage(const char *msg)183{184if(msg)185fprintf(stderr, "%s\n", msg);186fprintf(stderr,187"usage: [options] url\n"188" upload and pause, options:\n"189" -V http_version (http/1.1, h2, h3) http version to use\n"190);191}192193#define ERR() \194do { \195fprintf(stderr, "something unexpected went wrong - bailing out!\n"); \196return 2; \197} while(0)198199#endif /* !_MSC_VER */200201int main(int argc, char *argv[])202{203#ifndef _MSC_VER204CURL *curl;205CURLcode rc = CURLE_OK;206CURLU *cu;207struct curl_slist *resolve = NULL;208char resolve_buf[1024];209char *url, *host = NULL, *port = NULL;210long http_version = CURL_HTTP_VERSION_1_1;211int ch;212213while((ch = getopt(argc, argv, "V:")) != -1) {214switch(ch) {215case 'V': {216if(!strcmp("http/1.1", optarg))217http_version = CURL_HTTP_VERSION_1_1;218else if(!strcmp("h2", optarg))219http_version = CURL_HTTP_VERSION_2_0;220else if(!strcmp("h3", optarg))221http_version = CURL_HTTP_VERSION_3ONLY;222else {223usage("invalid http version");224return 1;225}226break;227}228default:229usage("invalid option");230return 1;231}232}233argc -= optind;234argv += optind;235236if(argc != 1) {237usage("not enough arguments");238return 2;239}240url = argv[0];241242curl_global_init(CURL_GLOBAL_DEFAULT);243curl_global_trace("ids,time");244245cu = curl_url();246if(!cu) {247fprintf(stderr, "out of memory\n");248return 1;249}250if(curl_url_set(cu, CURLUPART_URL, url, 0)) {251fprintf(stderr, "not a URL: '%s'\n", url);252return 1;253}254if(curl_url_get(cu, CURLUPART_HOST, &host, 0)) {255fprintf(stderr, "could not get host of '%s'\n", url);256return 1;257}258if(curl_url_get(cu, CURLUPART_PORT, &port, 0)) {259fprintf(stderr, "could not get port of '%s'\n", url);260return 1;261}262memset(&resolve, 0, sizeof(resolve));263curl_msnprintf(resolve_buf, sizeof(resolve_buf)-1, "%s:%s:127.0.0.1",264host, port);265resolve = curl_slist_append(resolve, resolve_buf);266267curl = curl_easy_init();268if(!curl) {269fprintf(stderr, "out of memory\n");270return 1;271}272/* We want to use our own read function. */273curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);274275/* It will help us to continue the read function. */276curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback);277curl_easy_setopt(curl, CURLOPT_XFERINFODATA, curl);278curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);279280/* It will help us to ensure that keepalive does not help. */281curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);282curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 1L);283curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 1L);284curl_easy_setopt(curl, CURLOPT_TCP_KEEPCNT, 1L);285286/* Enable uploading. */287curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");288curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);289290curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);291curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);292293if(curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L) != CURLE_OK ||294curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, debug_cb)295!= CURLE_OK ||296curl_easy_setopt(curl, CURLOPT_RESOLVE, resolve) != CURLE_OK)297ERR();298299curl_easy_setopt(curl, CURLOPT_URL, url);300curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, http_version);301302rc = curl_easy_perform(curl);303304if(curl) {305curl_easy_cleanup(curl);306}307308curl_slist_free_all(resolve);309curl_free(host);310curl_free(port);311curl_url_cleanup(cu);312curl_global_cleanup();313314return (int)rc;315#else316(void)argc;317(void)argv;318fprintf(stderr, "Not supported with this compiler.\n");319return 1;320#endif /* !_MSC_VER */321}322323324