Made -D option work with -O and -J.
[platform/upstream/curl.git] / src / tool_cb_hdr.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2012, 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 http://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 #include "tool_setup.h"
23
24 #include "rawstr.h"
25
26 #define ENABLE_CURLX_PRINTF
27 /* use our own printf() functions */
28 #include "curlx.h"
29
30 #include "tool_cfgable.h"
31 #include "tool_msgs.h"
32 #include "tool_cb_hdr.h"
33
34 #include "memdebug.h" /* keep this as LAST include */
35
36 static char *parse_filename(const char *ptr, size_t len);
37
38 /*
39 ** callback for CURLOPT_HEADERFUNCTION
40 */
41
42 size_t tool_header_cb(void *ptr, size_t size, size_t nmemb, void *userdata)
43 {
44   HeaderData *hdrdata = userdata;
45   struct getout *urlnode = hdrdata->urlnode;
46   struct OutStruct *outs = hdrdata->outs;
47   struct OutStruct *heads = hdrdata->heads;
48   const char *str = ptr;
49   const size_t cb = size * nmemb;
50   const char *end = (char*)ptr + cb;
51
52   /*
53    * Once that libcurl has called back tool_header_cb() the returned value
54    * is checked against the amount that was intended to be written, if
55    * it does not match then it fails with CURLE_WRITE_ERROR. So at this
56    * point returning a value different from sz*nmemb indicates failure.
57    */
58   size_t failure = (size * nmemb) ? 0 : 1;
59
60   if(!outs->config)
61     return failure;
62
63 #ifdef DEBUGBUILD
64   if(size * nmemb > (size_t)CURL_MAX_HTTP_HEADER) {
65     warnf(outs->config, "Header data exceeds single call write limit!\n");
66     return failure;
67   }
68 #endif
69   /* --dump-header option */
70   if(outs->config->headerfile) {
71     fwrite(ptr, size, nmemb, heads->stream);
72   }
73
74   if((urlnode->flags & GETOUT_USEREMOTE) && outs->config->content_disposition
75      && (cb > 20) && checkprefix("Content-disposition:", str)) {
76     const char *p = str + 20;
77
78     /* look for the 'filename=' parameter
79        (encoded filenames (*=) are not supported) */
80     for(;;) {
81       char *filename;
82       size_t len;
83
84       while(*p && (p < end) && !ISALPHA(*p))
85         p++;
86       if(p > end - 9)
87         break;
88
89       if(memcmp(p, "filename=", 9)) {
90         /* no match, find next parameter */
91         while((p < end) && (*p != ';'))
92           p++;
93         continue;
94       }
95       p += 9;
96
97       /* this expression below typecasts 'cb' only to avoid
98          warning: signed and unsigned type in conditional expression
99       */
100       len = (ssize_t)cb - (p - str);
101       filename = parse_filename(p, len);
102       if(filename) {
103         outs->filename = filename;
104         outs->alloc_filename = TRUE;
105         outs->s_isreg = TRUE;
106         outs->fopened = FALSE;
107         outs->stream = NULL;
108         break;
109       }
110       else
111         return failure;
112     }
113   }
114
115   return cb;
116 }
117
118 /*
119  * Copies a file name part and returns an ALLOCATED data buffer.
120  */
121 static char *parse_filename(const char *ptr, size_t len)
122 {
123   char *copy;
124   char *p;
125   char *q;
126   char  stop = '\0';
127
128   /* simple implementation of strndup() */
129   copy = malloc(len+1);
130   if(!copy)
131     return NULL;
132   memcpy(copy, ptr, len);
133   copy[len] = '\0';
134
135   p = copy;
136   if(*p == '\'' || *p == '"') {
137     /* store the starting quote */
138     stop = *p;
139     p++;
140   }
141   else
142     stop = ';';
143
144   /* if the filename contains a path, only use filename portion */
145   q = strrchr(copy, '/');
146   if(q) {
147     p = q + 1;
148     if(!*p) {
149       Curl_safefree(copy);
150       return NULL;
151     }
152   }
153
154   /* If the filename contains a backslash, only use filename portion. The idea
155      is that even systems that don't handle backslashes as path separators
156      probably want the path removed for convenience. */
157   q = strrchr(p, '\\');
158   if(q) {
159     p = q + 1;
160     if(!*p) {
161       Curl_safefree(copy);
162       return NULL;
163     }
164   }
165
166   /* scan for the end letter and stop there */
167   q = p;
168   while(*q) {
169     if(q[1] && (q[0] == '\\'))
170       q++;
171     else if(q[0] == stop)
172       break;
173     q++;
174   }
175   *q = '\0';
176
177   /* make sure the file name doesn't end in \r or \n */
178   q = strchr(p, '\r');
179   if(q)
180     *q = '\0';
181
182   q = strchr(p, '\n');
183   if(q)
184     *q = '\0';
185
186   if(copy != p)
187     memmove(copy, p, strlen(p) + 1);
188
189   /* in case we built debug enabled, we allow an evironment variable
190    * named CURL_TESTDIR to prefix the given file name to put it into a
191    * specific directory
192    */
193 #ifdef DEBUGBUILD
194   {
195     char *tdir = curlx_getenv("CURL_TESTDIR");
196     if(tdir) {
197       char buffer[512]; /* suitably large */
198       snprintf(buffer, sizeof(buffer), "%s/%s", tdir, copy);
199       Curl_safefree(copy);
200       copy = strdup(buffer); /* clone the buffer, we don't use the libcurl
201                                 aprintf() or similar since we want to use the
202                                 same memory code as the "real" parse_filename
203                                 function */
204       curl_free(tdir);
205     }
206   }
207 #endif
208
209   return copy;
210 }
211