Skip to content

Commit

Permalink
curl: show headers in bold
Browse files Browse the repository at this point in the history
The feature is only enabled if the output is believed to be a tty.

-J: There's some minor differences and improvements in -J handling, as
now J should work with -i and it actually creates a file first using the
initial name and then *renames* that to the one found in
Content-Disposition (if any).

-i: only shows headers for HTTP transfers now (as documented).
Previously it would also show for pieces of the transfer that were HTTP
(for example when doing FTP over a HTTP proxy).

-i: now shows trailers as well. Previously they were not shown at all.

--libcurl: the CURLOPT_HEADER is no longer set, as the header output is
now done in the header callback.
  • Loading branch information
bagder committed May 21, 2018
1 parent 6876ccf commit c1c2762
Show file tree
Hide file tree
Showing 22 changed files with 81 additions and 55 deletions.
63 changes: 52 additions & 11 deletions src/tool_cb_hdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
Expand All @@ -31,11 +31,20 @@
#include "tool_doswin.h"
#include "tool_msgs.h"
#include "tool_cb_hdr.h"
#include "tool_cb_wrt.h"

#include "memdebug.h" /* keep this as LAST include */

static char *parse_filename(const char *ptr, size_t len);

#ifdef WIN32

This comment has been minimized.

Copy link
@gvanem

gvanem May 22, 2018

Contributor

Is it safe to assume that MSDOS, __AMIGA__ etc. support ANSI?
And a little test using ConEmu/Win-10, shows that bold ANSI-sequences work fine.

This comment has been minimized.

Copy link
@bagder

bagder May 22, 2018

Author Member

I'm pretty sure it isn't a 100% safe assumption, but I rather wait for users on those platforms to act than having to guess or make code based on my assumptions.

This comment has been minimized.

Copy link
@gvanem

gvanem May 22, 2018

Contributor

One could turn BOLD and BOLDOFF into functions returning a const char*. Something like:

--- a/tool_cb_hdr.c 2018-05-22 08:43:49
+++ b/tool_cb_hdr.c 2018-05-22 09:58:06
@@ -37,14 +37,32 @@

 static char *parse_filename(const char *ptr, size_t len);

-#ifdef WIN32
-#define BOLD
-#define BOLDOFF
+#if defined(MSDOS) || defined(__AMIGA__)
+ #define have_ansi_support() 0
+
+#elif defined(_WIN32) 
+  static bool have_ansi_support (void)
+  {
+    static int yes_no = -1;
+    const char *env;
+
+    if (yes_no != -1)
+       return (yes_no);
+    env = curlx_getenv("ConEmuANSI");
+    yes_no = (env && !stricmp(env,"ON"));
+    return (yes_no);
+  }
 #else
-#define BOLD "\x1b[1m"
-#define BOLDOFF "\x1b[21m"
+  #define have_ansi_support() 0   /* Posix / OSX etc. */
 #endif

+static const char *set_bold (int on_off)
+{
+  if (!have_ansi_support())
+     return ("");
+  return (on_off ? "\x1b[1m" : "\x1b[21m");
+}
+
 /*
 ** callback for CURLOPT_HEADERFUNCTION
 */
@@ -167,7 +185,7 @@
       value = memchr(ptr, ':', cb);
     if(value) {
       size_t namelen = value - ptr;
-      fprintf(outs->stream, BOLD "%.*s" BOLDOFF ":", namelen, ptr);
+      fprintf(outs->stream, "%s%.*s%s:", set_bold(1), namelen, ptr, set_bold(0));
       fwrite(&value[1], cb - namelen - 1, 1, outs->stream);
     }
     else

And there are other ways to get ANSI-support under Windows. How to detect those are a bit more involved that just checking some env-vars. An ansi.sys under MSDOS can be detected using a special sequence.

This comment has been minimized.

Copy link
@bagder

bagder May 23, 2018

Author Member

Absolutely, something like that could work (with default saying support enabled I would guess). A downside with the getenv approach like this is that this can't switch off the escape sequences when piping the output into another program, or when redirecting, the way we can on posix. Maybe less of a problem on Windows since my impression is that users don't pipe as much there. Or can we do a isatty() thing on Windows too?

You up for making a "real" PR out of this? Would make more people notice and have a chance to weigh in on this...

#define BOLD
#define BOLDOFF
#else
#define BOLD "\x1b[1m"
#define BOLDOFF "\x1b[21m"
#endif

/*
** callback for CURLOPT_HEADERFUNCTION
*/
Expand All @@ -48,7 +57,7 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
const char *str = ptr;
const size_t cb = size * nmemb;
const char *end = (char *)ptr + cb;
char *url = NULL;
long protocol = 0;

/*
* Once that libcurl has called back tool_header_cb() the returned value
Expand Down Expand Up @@ -88,12 +97,15 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
* 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) &&
!curl_easy_getinfo(outs->config->easy, CURLINFO_EFFECTIVE_URL, &url) &&
url && (checkprefix("http://", url) || checkprefix("https://", url))) {
(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(;;) {
Expand All @@ -119,19 +131,49 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
len = (ssize_t)cb - (p - str);
filename = parse_filename(p, len);
if(filename) {
outs->filename = filename;
outs->alloc_filename = TRUE;
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->stream = NULL;
hdrcbdata->honor_cd_filename = FALSE;
break;
outs->filename = filename;
outs->alloc_filename = TRUE;
hdrcbdata->honor_cd_filename = FALSE; /* done now! */
if(!tool_create_output_file(outs, TRUE))
return failure;
}
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)
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;
}

Expand Down Expand Up @@ -233,4 +275,3 @@ static char *parse_filename(const char *ptr, size_t len)

return copy;
}

4 changes: 3 additions & 1 deletion src/tool_cb_hdr.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
Expand Down Expand Up @@ -39,6 +39,8 @@
*/

struct HdrCbData {
struct GlobalConfig *global;
struct OperationConfig *config;
struct OutStruct *outs;
struct OutStruct *heads;
bool honor_cd_filename;
Expand Down
13 changes: 7 additions & 6 deletions src/tool_cb_wrt.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
Expand All @@ -32,7 +32,8 @@
#include "memdebug.h" /* keep this as LAST include */

/* create a local file for writing, return TRUE on success */
bool tool_create_output_file(struct OutStruct *outs)
bool tool_create_output_file(struct OutStruct *outs,
bool append)
{
struct GlobalConfig *global = outs->config->global;
FILE *file;
Expand All @@ -42,7 +43,7 @@ bool tool_create_output_file(struct OutStruct *outs)
return FALSE;
}

if(outs->is_cd_filename) {
if(outs->is_cd_filename && !append) {
/* don't overwrite existing files */
file = fopen(outs->filename, "rb");
if(file) {
Expand All @@ -54,7 +55,7 @@ bool tool_create_output_file(struct OutStruct *outs)
}

/* open file for writing */
file = fopen(outs->filename, "wb");
file = fopen(outs->filename, append?"ab":"wb");
if(!file) {
warnf(global, "Failed to create the file %s: %s\n", outs->filename,
strerror(errno));
Expand Down Expand Up @@ -97,7 +98,7 @@ size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
}
}

if(config->include_headers) {
if(config->show_headers) {
if(bytes > (size_t)CURL_MAX_HTTP_HEADER) {
warnf(config->global, "Header data size exceeds single call write "
"limit!\n");
Expand Down Expand Up @@ -141,7 +142,7 @@ size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
}
#endif

if(!outs->stream && !tool_create_output_file(outs))
if(!outs->stream && !tool_create_output_file(outs, FALSE))
return failure;

if(is_tty && (outs->bytes < 2000) && !config->terminal_binary_ok) {
Expand Down
4 changes: 2 additions & 2 deletions src/tool_cb_wrt.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
Expand All @@ -30,7 +30,7 @@
size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata);

/* create a local file for writing, return TRUE on success */
bool tool_create_output_file(struct OutStruct *outs);
bool tool_create_output_file(struct OutStruct *outs, bool append);

#endif /* HEADER_CURL_TOOL_CB_WRT_H */

2 changes: 1 addition & 1 deletion src/tool_cfgable.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ struct OperationConfig {
bool use_ascii; /* select ascii or text transfer */
bool autoreferer; /* automatically set referer */
bool failonerror; /* fail on (HTTP) errors */
bool include_headers; /* send headers to data output */
bool show_headers; /* show headers to data output */
bool no_body; /* don't get the body */
bool dirlistonly; /* only get the FTP dir list */
bool followlocation; /* follow http redirects */
Expand Down
12 changes: 5 additions & 7 deletions src/tool_getparam.c
Original file line number Diff line number Diff line change
Expand Up @@ -1722,24 +1722,22 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
}
break;
case 'i':
config->include_headers = toggle; /* include the headers as well in the
general output stream */
config->show_headers = toggle; /* show the headers as well in the
general output stream */
break;
case 'j':
config->cookiesession = toggle;
break;
case 'I':
/*
* no_body will imply include_headers later on
*/
case 'I': /* --head */
config->no_body = toggle;
config->show_headers = toggle;
if(SetHTTPrequest(config,
(config->no_body)?HTTPREQ_HEAD:HTTPREQ_GET,
&config->httpreq))
return PARAM_BAD_USE;
break;
case 'J': /* --remote-header-name */
if(config->include_headers) {
if(config->show_headers) {
warnf(global,
"--include and --remote-header-name cannot be combined.\n");
return PARAM_BAD_USE;
Expand Down
15 changes: 5 additions & 10 deletions src/tool_operate.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
Expand Down Expand Up @@ -851,15 +851,8 @@ static CURLcode operate_do(struct GlobalConfig *global,
my_setopt(curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize);
my_setopt_str(curl, CURLOPT_URL, this_url); /* what to fetch */
my_setopt(curl, CURLOPT_NOPROGRESS, global->noprogress?1L:0L);
if(config->no_body) {
if(config->no_body)
my_setopt(curl, CURLOPT_NOBODY, 1L);
my_setopt(curl, CURLOPT_HEADER, 1L);
}
/* If --metalink is used, we ignore --include (headers in
output) option because mixing headers to the body will
confuse XML parser and/or hash check will fail. */
else if(!config->use_metalink)
my_setopt(curl, CURLOPT_HEADER, config->include_headers?1L:0L);

if(config->oauth_bearer)
my_setopt_str(curl, CURLOPT_XOAUTH2_BEARER, config->oauth_bearer);
Expand Down Expand Up @@ -1373,6 +1366,8 @@ static CURLcode operate_do(struct GlobalConfig *global,

hdrcbdata.outs = &outs;
hdrcbdata.heads = &heads;
hdrcbdata.global = global;
hdrcbdata.config = config;

my_setopt(curl, CURLOPT_HEADERFUNCTION, tool_header_cb);
my_setopt(curl, CURLOPT_HEADERDATA, &hdrcbdata);
Expand Down Expand Up @@ -1523,7 +1518,7 @@ static CURLcode operate_do(struct GlobalConfig *global,
/* do not create (or even overwrite) the file in case we get no
data because of unmet condition */
curl_easy_getinfo(curl, CURLINFO_CONDITION_UNMET, &cond_unmet);
if(!cond_unmet && !tool_create_output_file(&outs))
if(!cond_unmet && !tool_create_output_file(&outs, FALSE))
result = CURLE_WRITE_ERROR;
}

Expand Down
2 changes: 2 additions & 0 deletions tests/data/test1116
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ Transfer-Encoding: chunked
Connection: mooo

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccc
chunky-trailer: header data
another-header: yes
</datacheck>
</reply>

Expand Down
3 changes: 0 additions & 3 deletions tests/data/test1319
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@ body
</data>

<datacheck>
HTTP/1.1 200 Mighty fine indeed
pop3: sure hit me

From: me@somewhere
To: fake@nowhere

Expand Down
3 changes: 0 additions & 3 deletions tests/data/test1321
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@ body
yours sincerely
</data>
<datacheck>
HTTP/1.1 200 Mighty fine indeed
imap: sure hit me

From: me@somewhere
To: fake@nowhere

Expand Down
1 change: 0 additions & 1 deletion tests/data/test1400
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ int main(int argc, char *argv[])
hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
curl_easy_setopt(hnd, CURLOPT_URL, "http://%HOSTIP:%HTTPPORT/we/want/1400");
curl_easy_setopt(hnd, CURLOPT_HEADER, 1L);
curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped");
curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
Expand Down
1 change: 0 additions & 1 deletion tests/data/test1401
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ int main(int argc, char *argv[])
hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
curl_easy_setopt(hnd, CURLOPT_URL, "http://%HOSTIP:%HTTPPORT/we/want/1401");
curl_easy_setopt(hnd, CURLOPT_HEADER, 1L);
curl_easy_setopt(hnd, CURLOPT_USERPWD, "fake:user");
curl_easy_setopt(hnd, CURLOPT_HTTPAUTH, (long)CURLAUTH_BASIC);
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, slist1);
Expand Down
1 change: 0 additions & 1 deletion tests/data/test1402
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ int main(int argc, char *argv[])
hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
curl_easy_setopt(hnd, CURLOPT_URL, "http://%HOSTIP:%HTTPPORT/we/want/1402");
curl_easy_setopt(hnd, CURLOPT_HEADER, 1L);
curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, "foo=bar&baz=quux");
curl_easy_setopt(hnd, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)16);
curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped");
Expand Down
1 change: 0 additions & 1 deletion tests/data/test1403
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ int main(int argc, char *argv[])
hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
curl_easy_setopt(hnd, CURLOPT_URL, "http://%HOSTIP:%HTTPPORT/we/want/1403?foo=bar&baz=quux");
curl_easy_setopt(hnd, CURLOPT_HEADER, 1L);
curl_easy_setopt(hnd, CURLOPT_USERAGENT, "stripped");
curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
Expand Down
1 change: 0 additions & 1 deletion tests/data/test1404
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ int main(int argc, char *argv[])
hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
curl_easy_setopt(hnd, CURLOPT_URL, "http://%HOSTIP:%HTTPPORT/we/want/1404");
curl_easy_setopt(hnd, CURLOPT_HEADER, 1L);
mime1 = curl_mime_init(hnd);
part1 = curl_mime_addpart(mime1);
curl_mime_data(part1, "value", CURL_ZERO_TERMINATED);
Expand Down
1 change: 0 additions & 1 deletion tests/data/test1405
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ int main(int argc, char *argv[])
hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
curl_easy_setopt(hnd, CURLOPT_URL, "ftp://%HOSTIP:%FTPPORT/1405");
curl_easy_setopt(hnd, CURLOPT_HEADER, 1L);
curl_easy_setopt(hnd, CURLOPT_QUOTE, slist1);
curl_easy_setopt(hnd, CURLOPT_POSTQUOTE, slist2);
curl_easy_setopt(hnd, CURLOPT_PREQUOTE, slist3);
Expand Down
1 change: 0 additions & 1 deletion tests/data/test1406
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ int main(int argc, char *argv[])
curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
curl_easy_setopt(hnd, CURLOPT_INFILESIZE_LARGE, (curl_off_t)38);
curl_easy_setopt(hnd, CURLOPT_URL, "smtp://%HOSTIP:%SMTPPORT/1406");
curl_easy_setopt(hnd, CURLOPT_HEADER, 1L);
curl_easy_setopt(hnd, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
Expand Down
1 change: 0 additions & 1 deletion tests/data/test1407
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ int main(int argc, char *argv[])
hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
curl_easy_setopt(hnd, CURLOPT_URL, "pop3://%HOSTIP:%POP3PORT/1407");
curl_easy_setopt(hnd, CURLOPT_HEADER, 1L);
curl_easy_setopt(hnd, CURLOPT_DIRLISTONLY, 1L);
curl_easy_setopt(hnd, CURLOPT_USERPWD, "user:secret");
curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
Expand Down
1 change: 1 addition & 0 deletions tests/data/test1417
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Trailer: chunky-trailer
Connection: mooo

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccc
chunky-trailer: header data
</datacheck>
</reply>

Expand Down
Loading

0 comments on commit c1c2762

Please sign in to comment.