size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) { struct HdrCbData *hdrcbdata = userdata; struct OutStruct *outs = hdrcbdata->outs; struct OutStruct *heads = hdrcbdata->heads; const char *str = ptr; const size_t cb = size * nmemb; const char *end = (char *)ptr + cb; long protocol = 0; /* * Once that libcurl has called back tool_header_cb() the returned value * is checked against the amount that was intended to be written, if * it does not match then it fails with CURLE_WRITE_ERROR. So at this * point returning a value different from sz*nmemb indicates failure. */ size_t failure = (size && nmemb) ? 0 : 1; if(!heads->config) return failure; #ifdef DEBUGBUILD if(size * nmemb > (size_t)CURL_MAX_HTTP_HEADER) { warnf(heads->config->global, "Header data exceeds single call write " "limit!\n"); return failure; } #endif /* * Write header data when curl option --dump-header (-D) is given. */ if(heads->config->headerfile && heads->stream) { size_t rc = fwrite(ptr, size, nmemb, heads->stream); if(rc != cb) return rc; /* flush the stream to send off what we got earlier */ (void)fflush(heads->stream); } /* * This callback sets the filename where output shall be written when * curl options --remote-name (-O) and --remote-header-name (-J) have * been simultaneously given and additionally server returns an HTTP * Content-Disposition header specifying a filename property. */ curl_easy_getinfo(outs->config->easy, CURLINFO_PROTOCOL, &protocol); if(hdrcbdata->honor_cd_filename && (cb > 20) && checkprefix("Content-disposition:", str) && (protocol & (CURLPROTO_HTTPS|CURLPROTO_HTTP))) { const char *p = str + 20; if(!outs->stream && !tool_create_output_file(outs, FALSE)) return failure; /* look for the 'filename=' parameter (encoded filenames (*=) are not supported) */ for(;;) { char *filename; size_t len; while(*p && (p < end) && !ISALPHA(*p)) p++; if(p > end - 9) break; if(memcmp(p, "filename=", 9)) { /* no match, find next parameter */ while((p < end) && (*p != ';')) p++; continue; } p += 9; /* this expression below typecasts 'cb' only to avoid warning: signed and unsigned type in conditional expression */ len = (ssize_t)cb - (p - str); filename = parse_filename(p, len); if(filename) { if(outs->stream) { /* already opened and possibly written to */ if(outs->fopened) fclose(outs->stream); outs->stream = NULL; /* rename the initial file name to the new file name */ rename(outs->filename, filename); if(outs->alloc_filename) free(outs->filename); } outs->is_cd_filename = TRUE; outs->s_isreg = TRUE; outs->fopened = FALSE; outs->filename = filename; outs->alloc_filename = TRUE; hdrcbdata->honor_cd_filename = FALSE; /* done now! */ if(!tool_create_output_file(outs, TRUE)) return failure; } break; } } if(hdrcbdata->config->show_headers && (protocol & (CURLPROTO_HTTP|CURLPROTO_HTTPS|CURLPROTO_RTSP))) { /* bold headers only happen for HTTP(S) and RTSP */ char *value = NULL; if(!outs->stream && !tool_create_output_file(outs, FALSE)) return failure; if(hdrcbdata->global->isatty && hdrcbdata->global->styled_output) value = memchr(ptr, ':', cb); if(value) { size_t namelen = value - ptr; fprintf(outs->stream, BOLD "%.*s" BOLDOFF ":", namelen, ptr); fwrite(&value[1], cb - namelen - 1, 1, outs->stream); } else /* not "handled", just show it */ fwrite(ptr, cb, 1, outs->stream); } return cb; }
size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata) { size_t rc; struct OutStruct *outs = userdata; struct OperationConfig *config = outs->config; size_t bytes = sz * nmemb; bool is_tty = config->global->isatty; /* * Once that libcurl has called back tool_write_cb() the returned value * is checked against the amount that was intended to be written, if * it does not match then it fails with CURLE_WRITE_ERROR. So at this * point returning a value different from sz*nmemb indicates failure. */ const size_t failure = bytes ? 0 : 1; #ifdef DEBUGBUILD { char *tty = curlx_getenv("CURL_ISATTY"); if(tty) { is_tty = TRUE; curl_free(tty); } } if(config->show_headers) { if(bytes > (size_t)CURL_MAX_HTTP_HEADER) { warnf(config->global, "Header data size exceeds single call write " "limit!\n"); return failure; } } else { if(bytes > (size_t)CURL_MAX_WRITE_SIZE) { warnf(config->global, "Data size exceeds single call write limit!\n"); return failure; } } { /* Some internal congruency checks on received OutStruct */ bool check_fails = FALSE; if(outs->filename) { /* regular file */ if(!*outs->filename) check_fails = TRUE; if(!outs->s_isreg) check_fails = TRUE; if(outs->fopened && !outs->stream) check_fails = TRUE; if(!outs->fopened && outs->stream) check_fails = TRUE; if(!outs->fopened && outs->bytes) check_fails = TRUE; } else { /* standard stream */ if(!outs->stream || outs->s_isreg || outs->fopened) check_fails = TRUE; if(outs->alloc_filename || outs->is_cd_filename || outs->init) check_fails = TRUE; } if(check_fails) { warnf(config->global, "Invalid output struct data for write callback\n"); return failure; } } #endif if(!outs->stream && !tool_create_output_file(outs)) return failure; if(is_tty && (outs->bytes < 2000) && !config->terminal_binary_ok) { /* binary output to terminal? */ if(memchr(buffer, 0, bytes)) { warnf(config->global, "Binary output can mess up your terminal. " "Use \"--output -\" to tell curl to output it to your terminal " "anyway, or consider \"--output <FILE>\" to save to a file.\n"); config->synthetic_error = ERR_BINARY_TERMINAL; return failure; } } #ifdef _WIN32 if(isatty(fileno(outs->stream))) { DWORD in_len = (DWORD)(sz * nmemb); wchar_t* wc_buf; DWORD wc_len; intptr_t fhnd; /* calculate buffer size for wide characters */ wc_len = MultiByteToWideChar(CP_UTF8, 0, buffer, in_len, NULL, 0); wc_buf = (wchar_t*) malloc(wc_len * sizeof(wchar_t)); if(!wc_buf) return failure; /* calculate buffer size for multi-byte characters */ wc_len = MultiByteToWideChar(CP_UTF8, 0, buffer, in_len, wc_buf, wc_len); if(!wc_len) { free(wc_buf); return failure; } fhnd = _get_osfhandle(fileno(outs->stream)); if(!WriteConsoleW( (HANDLE) fhnd, wc_buf, wc_len, &wc_len, NULL)) { free(wc_buf); return failure; } free(wc_buf); rc = bytes; } else #endif rc = fwrite(buffer, sz, nmemb, outs->stream); if(bytes == rc) /* we added this amount of data to the output */ outs->bytes += bytes; if(config->readbusy) { config->readbusy = FALSE; curl_easy_pause(config->easy, CURLPAUSE_CONT); } if(config->nobuffer) { /* output buffering disabled */ int res = fflush(outs->stream); if(res) return failure; } return rc; }