1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24/* argv1 = URL 25 * argv2 = proxy with embedded user+password 26 */ 27 28#include "test.h" 29 30#include "warnless.h" 31#include "memdebug.h" 32 33struct data { 34 char trace_ascii; /* 1 or 0 */ 35}; 36 37static 38void dump(const char *text, 39 FILE *stream, unsigned char *ptr, size_t size, 40 char nohex) 41{ 42 size_t i; 43 size_t c; 44 45 unsigned int width = 0x10; 46 47 if(nohex) 48 /* without the hex output, we can fit more on screen */ 49 width = 0x40; 50 51 fprintf(stream, "%s, %zu bytes (0x%zx)\n", text, size, size); 52 53 for(i = 0; i<size; i += width) { 54 55 fprintf(stream, "%04zx: ", i); 56 57 if(!nohex) { 58 /* hex not disabled, show it */ 59 for(c = 0; c < width; c++) 60 if(i + c < size) 61 fprintf(stream, "%02x ", ptr[i + c]); 62 else 63 fputs(" ", stream); 64 } 65 66 for(c = 0; (c < width) && (i + c < size); c++) { 67 /* check for 0D0A; if found, skip past and start a new line of output */ 68 if(nohex && (i + c + 1 < size) && ptr[i + c] == 0x0D && 69 ptr[i + c + 1] == 0x0A) { 70 i += (c + 2 - width); 71 break; 72 } 73 fprintf(stream, "%c", 74 (ptr[i + c] >= 0x20) && (ptr[i + c]<0x80)? ptr[i + c] : '.'); 75 /* check again for 0D0A, to avoid an extra \n if it's at width */ 76 if(nohex && (i + c + 2 < size) && ptr[i + c + 1] == 0x0D && 77 ptr[i + c + 2] == 0x0A) { 78 i += (c + 3 - width); 79 break; 80 } 81 } 82 fputc('\n', stream); /* newline */ 83 } 84 fflush(stream); 85} 86 87static 88int my_trace(CURL *handle, curl_infotype type, 89 char *data, size_t size, 90 void *userp) 91{ 92 struct data *config = (struct data *)userp; 93 const char *text; 94 (void)handle; /* prevent compiler warning */ 95 96 switch(type) { 97 case CURLINFO_TEXT: 98 fprintf(stderr, "== Info: %s", (char *)data); 99 return 0; 100 case CURLINFO_HEADER_OUT: 101 text = "=> Send header"; 102 break; 103 case CURLINFO_DATA_OUT: 104 text = "=> Send data"; 105 break; 106 case CURLINFO_SSL_DATA_OUT: 107 text = "=> Send SSL data"; 108 break; 109 case CURLINFO_HEADER_IN: 110 text = "<= Recv header"; 111 break; 112 case CURLINFO_DATA_IN: 113 text = "<= Recv data"; 114 break; 115 case CURLINFO_SSL_DATA_IN: 116 text = "<= Recv SSL data"; 117 break; 118 default: /* in case a new one is introduced to shock us */ 119 return 0; 120 } 121 122 dump(text, stderr, (unsigned char *)data, size, config->trace_ascii); 123 return 0; 124} 125 126 127static size_t current_offset = 0; 128static char databuf[70000]; /* MUST be more than 64k OR 129 MAX_INITIAL_POST_SIZE */ 130 131static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *stream) 132{ 133 size_t amount = nmemb * size; /* Total bytes curl wants */ 134 size_t available = sizeof(databuf) - current_offset; /* What we have to 135 give */ 136 size_t given = amount < available ? amount : available; /* What is given */ 137 (void)stream; 138 memcpy(ptr, databuf + current_offset, given); 139 current_offset += given; 140 return given; 141} 142 143 144static size_t write_callback(void *ptr, size_t size, size_t nmemb, 145 void *stream) 146{ 147 int amount = curlx_uztosi(size * nmemb); 148 printf("%.*s", amount, (char *)ptr); 149 (void)stream; 150 return size * nmemb; 151} 152 153 154static curlioerr ioctl_callback(CURL *handle, int cmd, void *clientp) 155{ 156 (void)clientp; 157 if(cmd == CURLIOCMD_RESTARTREAD) { 158 printf("APPLICATION received a CURLIOCMD_RESTARTREAD request\n"); 159 printf("APPLICATION ** REWINDING! **\n"); 160 current_offset = 0; 161 return CURLIOE_OK; 162 } 163 (void)handle; 164 return CURLIOE_UNKNOWNCMD; 165} 166 167 168 169int test(char *URL) 170{ 171 CURL *curl; 172 CURLcode res = CURLE_OK; 173 struct data config; 174 size_t i; 175 static const char fill[] = "test data"; 176 177 config.trace_ascii = 1; /* enable ascii tracing */ 178 179 global_init(CURL_GLOBAL_ALL); 180 easy_init(curl); 181 182 test_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace); 183 test_setopt(curl, CURLOPT_DEBUGDATA, &config); 184 /* the DEBUGFUNCTION has no effect until we enable VERBOSE */ 185 test_setopt(curl, CURLOPT_VERBOSE, 1L); 186 187 /* setup repeated data string */ 188 for(i = 0; i < sizeof(databuf); ++i) 189 databuf[i] = fill[i % sizeof(fill)]; 190 191 /* Post */ 192 test_setopt(curl, CURLOPT_POST, 1L); 193 194 /* Setup read callback */ 195 test_setopt(curl, CURLOPT_POSTFIELDSIZE, (long) sizeof(databuf)); 196 test_setopt(curl, CURLOPT_READFUNCTION, read_callback); 197 198 /* Write callback */ 199 test_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); 200 201 /* Ioctl function */ 202 CURL_IGNORE_DEPRECATION( 203 test_setopt(curl, CURLOPT_IOCTLFUNCTION, ioctl_callback); 204 ) 205 206 test_setopt(curl, CURLOPT_PROXY, libtest_arg2); 207 208 test_setopt(curl, CURLOPT_URL, URL); 209 210 /* Accept any auth. But for this bug configure proxy with DIGEST, basic 211 might work too, not NTLM */ 212 test_setopt(curl, CURLOPT_PROXYAUTH, (long)CURLAUTH_ANY); 213 214 res = curl_easy_perform(curl); 215 216test_cleanup: 217 218 curl_easy_cleanup(curl); 219 curl_global_cleanup(); 220 return (int)res; 221} 222