00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029
00030
00031 #include <sys/time.h>
00032 #include <unistd.h>
00033
00034
00035 #include <curl/curl.h>
00036
00037 #ifndef CURLPIPE_MULTIPLEX
00038 #error "too old libcurl, can't do HTTP/2 server push!"
00039 #endif
00040
00041 static
00042 void dump(const char *text, unsigned char *ptr, size_t size,
00043 char nohex)
00044 {
00045 size_t i;
00046 size_t c;
00047
00048 unsigned int width=0x10;
00049
00050 if(nohex)
00051
00052 width = 0x40;
00053
00054 fprintf(stderr, "%s, %ld bytes (0x%lx)\n",
00055 text, (long)size, (long)size);
00056
00057 for(i=0; i<size; i+= width) {
00058
00059 fprintf(stderr, "%4.4lx: ", (long)i);
00060
00061 if(!nohex) {
00062
00063 for(c = 0; c < width; c++)
00064 if(i+c < size)
00065 fprintf(stderr, "%02x ", ptr[i+c]);
00066 else
00067 fputs(" ", stderr);
00068 }
00069
00070 for(c = 0; (c < width) && (i+c < size); c++) {
00071
00072 if(nohex && (i+c+1 < size) && ptr[i+c]==0x0D && ptr[i+c+1]==0x0A) {
00073 i+=(c+2-width);
00074 break;
00075 }
00076 fprintf(stderr, "%c",
00077 (ptr[i+c]>=0x20) && (ptr[i+c]<0x80)?ptr[i+c]:'.');
00078
00079 if(nohex && (i+c+2 < size) && ptr[i+c+1]==0x0D && ptr[i+c+2]==0x0A) {
00080 i+=(c+3-width);
00081 break;
00082 }
00083 }
00084 fputc('\n', stderr);
00085 }
00086 }
00087
00088 static
00089 int my_trace(CURL *handle, curl_infotype type,
00090 char *data, size_t size,
00091 void *userp)
00092 {
00093 const char *text;
00094 (void)handle;
00095 (void)userp;
00096 switch(type) {
00097 case CURLINFO_TEXT:
00098 fprintf(stderr, "== Info: %s", data);
00099 default:
00100 return 0;
00101
00102 case CURLINFO_HEADER_OUT:
00103 text = "=> Send header";
00104 break;
00105 case CURLINFO_DATA_OUT:
00106 text = "=> Send data";
00107 break;
00108 case CURLINFO_SSL_DATA_OUT:
00109 text = "=> Send SSL data";
00110 break;
00111 case CURLINFO_HEADER_IN:
00112 text = "<= Recv header";
00113 break;
00114 case CURLINFO_DATA_IN:
00115 text = "<= Recv data";
00116 break;
00117 case CURLINFO_SSL_DATA_IN:
00118 text = "<= Recv SSL data";
00119 break;
00120 }
00121
00122 dump(text, (unsigned char *)data, size, 1);
00123 return 0;
00124 }
00125
00126 #define OUTPUTFILE "dl"
00127
00128 static void setup(CURL *hnd)
00129 {
00130 FILE *out = fopen(OUTPUTFILE, "wb");
00131
00132
00133 curl_easy_setopt(hnd, CURLOPT_WRITEDATA, out);
00134
00135
00136 curl_easy_setopt(hnd, CURLOPT_URL, "https://localhost:8443/index.html");
00137
00138
00139 curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
00140 curl_easy_setopt(hnd, CURLOPT_DEBUGFUNCTION, my_trace);
00141
00142
00143 curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
00144
00145
00146 curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L);
00147 curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L);
00148
00149 #if (CURLPIPE_MULTIPLEX > 0)
00150
00151 curl_easy_setopt(hnd, CURLOPT_PIPEWAIT, 1L);
00152 #endif
00153
00154 }
00155
00156
00157 static int server_push_callback(CURL *parent,
00158 CURL *easy,
00159 size_t num_headers,
00160 struct curl_pushheaders *headers,
00161 void *userp)
00162 {
00163 char *headp;
00164 size_t i;
00165 int *transfers = (int *)userp;
00166 char filename[128];
00167 FILE *out;
00168 static unsigned int count = 0;
00169
00170 (void)parent;
00171
00172 snprintf(filename, 128, "push%u", count++);
00173
00174
00175 out = fopen(filename, "wb");
00176
00177
00178 curl_easy_setopt(easy, CURLOPT_WRITEDATA, out);
00179
00180 fprintf(stderr, "**** push callback approves stream %u, got %d headers!\n",
00181 count, (int)num_headers);
00182
00183 for(i=0; i<num_headers; i++) {
00184 headp = curl_pushheader_bynum(headers, i);
00185 fprintf(stderr, "**** header %u: %s\n", (int)i, headp);
00186 }
00187
00188 headp = curl_pushheader_byname(headers, ":path");
00189 if(headp) {
00190 fprintf(stderr, "**** The PATH is %s\n", headp );
00191 }
00192
00193 (*transfers)++;
00194 return CURL_PUSH_OK;
00195 }
00196
00197
00198
00199
00200
00201 int main(void)
00202 {
00203 CURL *easy;
00204 CURLM *multi_handle;
00205 int still_running;
00206 int transfers=1;
00207 struct CURLMsg *m;
00208
00209
00210 multi_handle = curl_multi_init();
00211
00212 easy = curl_easy_init();
00213
00214
00215 setup(easy);
00216
00217
00218 curl_multi_add_handle(multi_handle, easy);
00219
00220 curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
00221 curl_multi_setopt(multi_handle, CURLMOPT_PUSHFUNCTION, server_push_callback);
00222 curl_multi_setopt(multi_handle, CURLMOPT_PUSHDATA, &transfers);
00223
00224
00225 curl_multi_perform(multi_handle, &still_running);
00226
00227 do {
00228 struct timeval timeout;
00229 int rc;
00230 CURLMcode mc;
00231
00232 fd_set fdread;
00233 fd_set fdwrite;
00234 fd_set fdexcep;
00235 int maxfd = -1;
00236
00237 long curl_timeo = -1;
00238
00239 FD_ZERO(&fdread);
00240 FD_ZERO(&fdwrite);
00241 FD_ZERO(&fdexcep);
00242
00243
00244 timeout.tv_sec = 1;
00245 timeout.tv_usec = 0;
00246
00247 curl_multi_timeout(multi_handle, &curl_timeo);
00248 if(curl_timeo >= 0) {
00249 timeout.tv_sec = curl_timeo / 1000;
00250 if(timeout.tv_sec > 1)
00251 timeout.tv_sec = 1;
00252 else
00253 timeout.tv_usec = (curl_timeo % 1000) * 1000;
00254 }
00255
00256
00257 mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
00258
00259 if(mc != CURLM_OK) {
00260 fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc);
00261 break;
00262 }
00263
00264
00265
00266
00267
00268
00269
00270 if(maxfd == -1) {
00271 #ifdef _WIN32
00272 Sleep(100);
00273 rc = 0;
00274 #else
00275
00276 struct timeval wait = { 0, 100 * 1000 };
00277 rc = select(0, NULL, NULL, NULL, &wait);
00278 #endif
00279 }
00280 else {
00281
00282
00283 rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
00284 }
00285
00286 switch(rc) {
00287 case -1:
00288
00289 break;
00290 case 0:
00291 default:
00292
00293 curl_multi_perform(multi_handle, &still_running);
00294 break;
00295 }
00296
00297
00298
00299
00300
00301
00302
00303 do {
00304 int msgq = 0;;
00305 m = curl_multi_info_read(multi_handle, &msgq);
00306 if(m && (m->msg == CURLMSG_DONE)) {
00307 CURL *e = m->easy_handle;
00308 transfers--;
00309 curl_multi_remove_handle(multi_handle, e);
00310 curl_easy_cleanup(e);
00311 }
00312 } while(m);
00313
00314 } while(transfers);
00315
00316 curl_multi_cleanup(multi_handle);
00317
00318
00319 return 0;
00320 }