284 } |
284 } |
285 |
285 |
286 static size_t util_header_callback(char *buffer, size_t size, |
286 static size_t util_header_callback(char *buffer, size_t size, |
287 size_t nitems, void *data) { |
287 size_t nitems, void *data) { |
288 |
288 |
289 char *duped; // local variable for string duplicates |
289 sstr_t sbuffer = sstrn(buffer, size*nitems); |
290 |
290 |
291 UcxMap *map = (UcxMap*) data; |
291 UcxMap *map = (UcxMap*) data; |
292 |
292 |
293 // if we get a status line, clear the map and exit |
293 // if we get a status line, clear the map and exit |
294 if(size*nitems >= 5 && !strncmp("HTTP/", buffer, 5)) { |
294 if(sstrprefix(sbuffer, S("HTTP/"))) { |
295 ucx_map_free_content(map, free); |
295 ucx_map_free_content(map, free); |
296 ucx_map_clear(map); |
296 ucx_map_clear(map); |
297 return size*nitems; |
297 return size*nitems; |
298 } |
298 } |
299 |
299 |
300 // if we get the terminating CRLF, just exit |
300 // if we get the terminating CRLF, just exit |
301 if (size*nitems == 2 && !strncmp("\r\n", buffer, 2)) { |
301 if(!sstrcmp(sbuffer, S("\r\n"))) { |
302 return 2; |
302 return 2; |
303 } |
303 } |
304 |
304 |
305 |
305 sstr_t key = sbuffer; |
306 // get header key |
306 sstr_t value = sstrchr(sbuffer, ':'); |
307 size_t s = 0; |
307 |
308 do { |
308 if(value.length == 0) { |
309 s++; |
309 return 0; // invalid header line |
310 } while(buffer[s] != ':'); |
310 } |
311 char *value = buffer+s+1; |
311 |
312 |
312 key.length = value.ptr - key.ptr; |
313 // remove trailing spaces |
313 value.ptr++; value.length--; |
314 while(isspace(buffer[s-1])) { |
314 |
315 s--; |
315 key = sstrdup(sstrtrim(key)); |
316 } |
316 value = sstrdup(sstrtrim(value)); |
317 |
317 |
318 // save key as all lower case |
318 for(size_t i = 0;i<key.length;i++) { |
319 duped = malloc(s); |
319 key.ptr[i] = tolower(key.ptr[i]); |
320 for(size_t i = 0;i<s;i++) { |
320 } |
321 duped[i] = tolower(buffer[i]); |
321 |
322 } |
322 ucx_map_sstr_put(map, key, value.ptr); |
323 UcxKey key = ucx_key(duped, s); |
323 |
324 |
324 free(key.ptr); |
325 // get trimmed header value |
325 |
326 while(isspace(*value)) { |
326 return sbuffer.length; |
327 value++; |
|
328 } |
|
329 s = size*nitems - (value - buffer); |
|
330 while(isspace(value[s-1])) { |
|
331 s--; |
|
332 } |
|
333 |
|
334 // copy header value and append NULL byte (curl does not provide one) |
|
335 duped = malloc(s+1); |
|
336 memcpy(duped, value, s+1); |
|
337 duped[s] = '\0'; |
|
338 |
|
339 char *oldval = ucx_map_get(map, key); |
|
340 if(oldval) { |
|
341 free(oldval); |
|
342 } |
|
343 |
|
344 ucx_map_put(map, key, duped); |
|
345 free(key.data); // ucx_map_put made a copy, so we free this memory |
|
346 |
|
347 return nitems * size; |
|
348 } |
327 } |
349 |
328 |
350 void util_capture_header(CURL *handle, UcxMap* map) { |
329 void util_capture_header(CURL *handle, UcxMap* map) { |
351 if(!map) { |
330 if(!map) { |
352 // deactivate capturing |
331 // deactivate capturing |