From 683cd7759f9bb4de957eecf3f159339b0c43f457 Mon Sep 17 00:00:00 2001 From: Nicolas Favre-Felix Date: Tue, 31 May 2011 20:50:07 +0200 Subject: [PATCH] Added Content-Disposition. --- client.c | 17 +++++++++++++++++ client.h | 1 + cmd.c | 5 +++++ cmd.h | 5 ++++- formats/common.c | 9 +++++++-- 5 files changed, 34 insertions(+), 3 deletions(-) diff --git a/client.c b/client.c index b8e19e7..8eecde2 100644 --- a/client.c +++ b/client.c @@ -72,6 +72,20 @@ http_client_on_header_name(struct http_parser *p, const char *at, size_t sz) { return 0; } +static char * +wrap_filename(const char *val, size_t val_len) { + + char format[] = "attachment; filename=\""; + size_t sz = sizeof(format) - 1 + val_len + 1; + char *p = calloc(sz + 1, 1); + + memcpy(p, format, sizeof(format)-1); /* copy format */ + memcpy(p + sizeof(format)-1, val, val_len); /* copy filename */ + p[sz-1] = '"'; + + return p; +} + /* * Split query string into key/value pairs, process some of them. */ @@ -109,6 +123,8 @@ http_client_on_query_string(struct http_parser *parser, const char *at, size_t s || (key_len == 8 && strncmp(key, "callback", 8) == 0)) { c->jsonp = calloc(1 + val_len, 1); memcpy(c->jsonp, val, val_len); + } else if(key_len == 8 && strncmp(key, "filename", 8) == 0) { + c->filename = wrap_filename(val, val_len); } if(!amp) { @@ -222,6 +238,7 @@ http_client_reset(struct http_client *c) { c->path_sz = 0; free(c->type); c->type = NULL; free(c->jsonp); c->jsonp = NULL; + free(c->filename); c->filename = NULL; /* no last known header callback */ c->last_cb = LAST_CB_NONE; diff --git a/client.h b/client.h index ce4e741..5e1d3db 100644 --- a/client.h +++ b/client.h @@ -50,6 +50,7 @@ struct http_client { char *type; /* forced output content-type */ char *jsonp; /* jsonp wrapper */ + char *filename; /* content-disposition */ struct cmd *pub_sub; }; diff --git a/cmd.c b/cmd.c index 30923bb..c309137 100644 --- a/cmd.c +++ b/cmd.c @@ -109,6 +109,11 @@ cmd_setup(struct cmd *cmd, struct http_client *client) { client->jsonp = NULL; } + if(client->filename) { /* transfer pointer ownership */ + cmd->filename = client->filename; + client->filename = NULL; + } + cmd->fd = client->fd; cmd->http_version = client->http_version; } diff --git a/cmd.h b/cmd.h index cc67536..ea293da 100644 --- a/cmd.h +++ b/cmd.h @@ -28,10 +28,13 @@ struct cmd { /* HTTP data */ char *mime; /* forced output content-type */ + int mime_free; /* need to free mime buffer */ + + char *filename; /* content-disposition attachment */ + char *if_none_match; /* used with ETags */ char *jsonp; /* jsonp wrapper */ int keep_alive; - int mime_free; /* need to free mime buffer */ /* various flags */ int started_responding; diff --git a/formats/common.c b/formats/common.c index 2e6ce13..3cd2e1a 100644 --- a/formats/common.c +++ b/formats/common.c @@ -56,6 +56,7 @@ format_send_reply(struct cmd *cmd, const char *p, size_t sz, const char *content int free_cmd = 1; struct http_response resp; + const char *ct = cmd->mime?cmd->mime:content_type; if(cmd->is_websocket) { ws_reply(cmd, p, sz); @@ -68,10 +69,12 @@ format_send_reply(struct cmd *cmd, const char *p, size_t sz, const char *content /* start streaming */ if(cmd->started_responding == 0) { - const char *ct = cmd->mime?cmd->mime:content_type; cmd->started_responding = 1; http_response_init(&resp, 200, "OK"); resp.http_version = cmd->http_version; + if(cmd->filename) { + http_response_set_header(&resp, "Content-Disposition", cmd->filename); + } http_response_set_header(&resp, "Content-Type", ct); http_response_set_keep_alive(&resp, 1); http_response_set_header(&resp, "Transfer-Encoding", "chunked"); @@ -88,8 +91,10 @@ format_send_reply(struct cmd *cmd, const char *p, size_t sz, const char *content /* SAME! send 304. */ http_response_init(&resp, 304, "Not Modified"); } else { - const char *ct = cmd->mime?cmd->mime:content_type; http_response_init(&resp, 200, "OK"); + if(cmd->filename) { + http_response_set_header(&resp, "Content-Disposition", cmd->filename); + } http_response_set_header(&resp, "Content-Type", ct); http_response_set_header(&resp, "ETag", etag); http_response_set_body(&resp, p, sz);