Return to http2-pushinmemory.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / docs / examples |
1.1 ! misho 1: /*************************************************************************** ! 2: * _ _ ____ _ ! 3: * Project ___| | | | _ \| | ! 4: * / __| | | | |_) | | ! 5: * | (__| |_| | _ <| |___ ! 6: * \___|\___/|_| \_\_____| ! 7: * ! 8: * Copyright (C) 1998 - 2018, 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.haxx.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: ***************************************************************************/ ! 22: /* <DESC> ! 23: * HTTP/2 server push. Receive all data in memory. ! 24: * </DESC> ! 25: */ ! 26: #include <stdio.h> ! 27: #include <stdlib.h> ! 28: #include <string.h> ! 29: ! 30: /* somewhat unix-specific */ ! 31: #include <sys/time.h> ! 32: #include <unistd.h> ! 33: ! 34: /* curl stuff */ ! 35: #include <curl/curl.h> ! 36: ! 37: struct Memory { ! 38: char *memory; ! 39: size_t size; ! 40: }; ! 41: ! 42: static size_t ! 43: write_cb(void *contents, size_t size, size_t nmemb, void *userp) ! 44: { ! 45: size_t realsize = size * nmemb; ! 46: struct Memory *mem = (struct Memory *)userp; ! 47: char *ptr = realloc(mem->memory, mem->size + realsize + 1); ! 48: if(!ptr) { ! 49: /* out of memory! */ ! 50: printf("not enough memory (realloc returned NULL)\n"); ! 51: return 0; ! 52: } ! 53: ! 54: mem->memory = ptr; ! 55: memcpy(&(mem->memory[mem->size]), contents, realsize); ! 56: mem->size += realsize; ! 57: mem->memory[mem->size] = 0; ! 58: ! 59: return realsize; ! 60: } ! 61: ! 62: #define MAX_FILES 10 ! 63: static struct Memory files[MAX_FILES]; ! 64: static int pushindex = 1; ! 65: ! 66: static void init_memory(struct Memory *chunk) ! 67: { ! 68: chunk->memory = malloc(1); /* grown as needed with realloc */ ! 69: chunk->size = 0; /* no data at this point */ ! 70: } ! 71: ! 72: static void setup(CURL *hnd) ! 73: { ! 74: /* set the same URL */ ! 75: curl_easy_setopt(hnd, CURLOPT_URL, "https://localhost:8443/index.html"); ! 76: ! 77: /* HTTP/2 please */ ! 78: curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); ! 79: ! 80: /* we use a self-signed test server, skip verification during debugging */ ! 81: curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L); ! 82: curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L); ! 83: ! 84: /* write data to a struct */ ! 85: curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, write_cb); ! 86: init_memory(&files[0]); ! 87: curl_easy_setopt(hnd, CURLOPT_WRITEDATA, &files[0]); ! 88: ! 89: /* wait for pipe connection to confirm */ ! 90: curl_easy_setopt(hnd, CURLOPT_PIPEWAIT, 1L); ! 91: } ! 92: ! 93: /* called when there's an incoming push */ ! 94: static int server_push_callback(CURL *parent, ! 95: CURL *easy, ! 96: size_t num_headers, ! 97: struct curl_pushheaders *headers, ! 98: void *userp) ! 99: { ! 100: char *headp; ! 101: int *transfers = (int *)userp; ! 102: (void)parent; /* we have no use for this */ ! 103: (void)num_headers; /* unused */ ! 104: ! 105: if(pushindex == MAX_FILES) ! 106: /* can't fit anymore */ ! 107: return CURL_PUSH_DENY; ! 108: ! 109: /* write to this buffer */ ! 110: init_memory(&files[pushindex]); ! 111: curl_easy_setopt(easy, CURLOPT_WRITEDATA, &files[pushindex]); ! 112: pushindex++; ! 113: ! 114: headp = curl_pushheader_byname(headers, ":path"); ! 115: if(headp) ! 116: fprintf(stderr, "* Pushed :path '%s'\n", headp /* skip :path + colon */); ! 117: ! 118: (*transfers)++; /* one more */ ! 119: return CURL_PUSH_OK; ! 120: } ! 121: ! 122: ! 123: /* ! 124: * Download a file over HTTP/2, take care of server push. ! 125: */ ! 126: int main(void) ! 127: { ! 128: CURL *easy; ! 129: CURLM *multi; ! 130: int still_running; /* keep number of running handles */ ! 131: int transfers = 1; /* we start with one */ ! 132: int i; ! 133: struct CURLMsg *m; ! 134: ! 135: /* init a multi stack */ ! 136: multi = curl_multi_init(); ! 137: ! 138: easy = curl_easy_init(); ! 139: ! 140: /* set options */ ! 141: setup(easy); ! 142: ! 143: /* add the easy transfer */ ! 144: curl_multi_add_handle(multi, easy); ! 145: ! 146: curl_multi_setopt(multi, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); ! 147: curl_multi_setopt(multi, CURLMOPT_PUSHFUNCTION, server_push_callback); ! 148: curl_multi_setopt(multi, CURLMOPT_PUSHDATA, &transfers); ! 149: ! 150: while(transfers) { ! 151: int rc; ! 152: CURLMcode mcode = curl_multi_perform(multi, &still_running); ! 153: if(mcode) ! 154: break; ! 155: ! 156: mcode = curl_multi_wait(multi, NULL, 0, 1000, &rc); ! 157: if(mcode) ! 158: break; ! 159: ! 160: ! 161: /* ! 162: * When doing server push, libcurl itself created and added one or more ! 163: * easy handles but *we* need to clean them up when they are done. ! 164: */ ! 165: do { ! 166: int msgq = 0;; ! 167: m = curl_multi_info_read(multi, &msgq); ! 168: if(m && (m->msg == CURLMSG_DONE)) { ! 169: CURL *e = m->easy_handle; ! 170: transfers--; ! 171: curl_multi_remove_handle(multi, e); ! 172: curl_easy_cleanup(e); ! 173: } ! 174: } while(m); ! 175: ! 176: } ! 177: ! 178: ! 179: curl_multi_cleanup(multi); ! 180: ! 181: /* 'pushindex' is now the number of received transfers */ ! 182: for(i = 0; i < pushindex; i++) { ! 183: /* do something fun with the data, and then free it when done */ ! 184: free(files[i].memory); ! 185: } ! 186: ! 187: return 0; ! 188: }