Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/external/curl/tests/libtest/cli_h2_serverpush.c
2649 views
1
/***************************************************************************
2
* _ _ ____ _
3
* Project ___| | | | _ \| |
4
* / __| | | | |_) | |
5
* | (__| |_| | _ <| |___
6
* \___|\___/|_| \_\_____|
7
*
8
* Copyright (C) Daniel Stenberg, <[email protected]>, 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 "first.h"
25
26
#include "testtrace.h"
27
#include "memdebug.h"
28
29
static FILE *out_download = NULL;
30
31
static int setup_h2_serverpush(CURL *curl, const char *url)
32
{
33
out_download = curlx_fopen("download_0.data", "wb");
34
if(!out_download)
35
return 1; /* failed */
36
37
curl_easy_setopt(curl, CURLOPT_URL, url);
38
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
39
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
40
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
41
42
curl_easy_setopt(curl, CURLOPT_WRITEDATA, out_download);
43
44
/* please be verbose */
45
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
46
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, libtest_debug_cb);
47
curl_easy_setopt(curl, CURLOPT_DEBUGDATA, &debug_config);
48
49
/* wait for pipe connection to confirm */
50
curl_easy_setopt(curl, CURLOPT_PIPEWAIT, 1L);
51
52
return 0; /* all is good */
53
}
54
55
static FILE *out_push = NULL;
56
57
/* called when there is an incoming push */
58
static int server_push_callback(CURL *parent,
59
CURL *curl,
60
size_t num_headers,
61
struct curl_pushheaders *headers,
62
void *userp)
63
{
64
char *headp;
65
size_t i;
66
int *transfers = (int *)userp;
67
char filename[128];
68
static unsigned int count = 0;
69
70
(void)parent;
71
72
curl_msnprintf(filename, sizeof(filename) - 1, "push%u", count++);
73
74
/* here's a new stream, save it in a new file for each new push */
75
out_push = curlx_fopen(filename, "wb");
76
if(!out_push) {
77
/* if we cannot save it, deny it */
78
curl_mfprintf(stderr, "Failed to create output file for push\n");
79
return CURL_PUSH_DENY;
80
}
81
82
/* write to this file */
83
curl_easy_setopt(curl, CURLOPT_WRITEDATA, out_push);
84
85
curl_mfprintf(stderr, "**** push callback approves stream %u, "
86
"got %zu headers!\n", count, num_headers);
87
88
for(i = 0; i < num_headers; i++) {
89
headp = curl_pushheader_bynum(headers, i);
90
curl_mfprintf(stderr, "**** header %zu: %s\n", i, headp);
91
}
92
93
headp = curl_pushheader_byname(headers, ":path");
94
if(headp) {
95
curl_mfprintf(stderr, "**** The PATH is %s\n",
96
headp /* skip :path + colon */);
97
}
98
99
(*transfers)++; /* one more */
100
101
return CURL_PUSH_OK;
102
}
103
104
/*
105
* Download a file over HTTP/2, take care of server push.
106
*/
107
static CURLcode test_cli_h2_serverpush(const char *URL)
108
{
109
CURL *curl = NULL;
110
CURLM *multi;
111
int transfers = 1; /* we start with one */
112
CURLcode result = CURLE_OK;
113
114
debug_config.nohex = TRUE;
115
debug_config.tracetime = FALSE;
116
117
if(!URL) {
118
curl_mfprintf(stderr, "need URL as argument\n");
119
return (CURLcode)2;
120
}
121
122
if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
123
curl_mfprintf(stderr, "curl_global_init() failed\n");
124
return (CURLcode)3;
125
}
126
127
multi = curl_multi_init();
128
if(!multi) {
129
result = (CURLcode)1;
130
goto cleanup;
131
}
132
133
curl = curl_easy_init();
134
if(!curl) {
135
result = (CURLcode)1;
136
goto cleanup;
137
}
138
139
if(setup_h2_serverpush(curl, URL)) {
140
curl_mfprintf(stderr, "failed\n");
141
result = (CURLcode)1;
142
goto cleanup;
143
}
144
145
curl_multi_setopt(multi, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
146
curl_multi_setopt(multi, CURLMOPT_PUSHFUNCTION, server_push_callback);
147
curl_multi_setopt(multi, CURLMOPT_PUSHDATA, &transfers);
148
149
curl_multi_add_handle(multi, curl);
150
151
do {
152
struct CURLMsg *m;
153
int still_running; /* keep number of running handles */
154
CURLMcode mc = curl_multi_perform(multi, &still_running);
155
156
if(still_running)
157
/* wait for activity, timeout or "nothing" */
158
mc = curl_multi_poll(multi, NULL, 0, 1000, NULL);
159
160
if(mc)
161
break;
162
163
/*
164
* A little caution when doing server push is that libcurl itself has
165
* created and added one or more easy handles but we need to clean them up
166
* when we are done.
167
*/
168
do {
169
int msgq = 0;
170
m = curl_multi_info_read(multi, &msgq);
171
if(m && (m->msg == CURLMSG_DONE)) {
172
CURL *easy = m->easy_handle;
173
transfers--;
174
curl_multi_remove_handle(multi, easy);
175
curl_easy_cleanup(easy);
176
}
177
} while(m);
178
179
} while(transfers); /* as long as we have transfers going */
180
181
cleanup:
182
183
curl_multi_cleanup(multi);
184
185
if(out_download)
186
curlx_fclose(out_download);
187
if(out_push)
188
curlx_fclose(out_push);
189
190
curl_global_cleanup();
191
192
return result;
193
}
194
195