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 #include "test.h"
25
26 #include "testutil.h"
27 #include "warnless.h"
28 #include "memdebug.h"
29
30 struct transfer_status {
31 CURL *easy;
32 curl_off_t out_len;
33 size_t hd_line;
34 CURLcode result;
35 int http_status;
36 };
37
header_callback(char * ptr,size_t size,size_t nmemb,void * userp)38 static size_t header_callback(char *ptr, size_t size, size_t nmemb,
39 void *userp)
40 {
41 struct transfer_status *st = (struct transfer_status *)userp;
42 const char *hd = ptr;
43 size_t len = size * nmemb;
44 CURLcode result;
45
46 (void)fwrite(ptr, size, nmemb, stdout);
47 ++st->hd_line;
48 if(len == 2 && hd[0] == '\r' && hd[1] == '\n') {
49 curl_off_t clen;
50 long httpcode = 0;
51 /* end of a response */
52 result = curl_easy_getinfo(st->easy, CURLINFO_RESPONSE_CODE, &httpcode);
53 fprintf(stderr, "header_callback, get status: %ld, %d\n",
54 httpcode, result);
55 if(httpcode < 100 || httpcode >= 1000) {
56 fprintf(stderr, "header_callback, invalid status: %ld, %d\n",
57 httpcode, result);
58 return CURLE_WRITE_ERROR;
59 }
60 st->http_status = (int)httpcode;
61 if(st->http_status >= 200 && st->http_status < 300) {
62 result = curl_easy_getinfo(st->easy, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T,
63 &clen);
64 fprintf(stderr, "header_callback, info Content-Length: %ld, %d\n",
65 (long)clen, result);
66 if(result) {
67 st->result = result;
68 return CURLE_WRITE_ERROR;
69 }
70 if(clen < 0) {
71 fprintf(stderr, "header_callback, expected known Content-Length, "
72 "got: %ld\n", (long)clen);
73 return CURLE_WRITE_ERROR;
74 }
75 }
76 }
77 return len;
78 }
79
write_callback(char * ptr,size_t size,size_t nmemb,void * userp)80 static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userp)
81 {
82 struct transfer_status *st = (struct transfer_status *)userp;
83 size_t len = size * nmemb;
84 fwrite(ptr, size, nmemb, stdout);
85 st->out_len += (curl_off_t)len;
86 return len;
87 }
88
test(char * URL)89 CURLcode test(char *URL)
90 {
91 CURL *curls = NULL;
92 CURLcode res = CURLE_OK;
93 struct transfer_status st;
94
95 start_test_timing();
96
97 memset(&st, 0, sizeof(st));
98
99 global_init(CURL_GLOBAL_ALL);
100
101 easy_init(curls);
102 st.easy = curls; /* to allow callbacks access */
103
104 easy_setopt(curls, CURLOPT_URL, URL);
105 easy_setopt(curls, CURLOPT_WRITEFUNCTION, write_callback);
106 easy_setopt(curls, CURLOPT_WRITEDATA, &st);
107 easy_setopt(curls, CURLOPT_HEADERFUNCTION, header_callback);
108 easy_setopt(curls, CURLOPT_HEADERDATA, &st);
109
110 easy_setopt(curls, CURLOPT_NOPROGRESS, 1L);
111
112 res = curl_easy_perform(curls);
113
114 test_cleanup:
115
116 curl_easy_cleanup(curls);
117 curl_global_cleanup();
118
119 return res; /* return the final return code */
120 }
121