remove short-lived CURL_WRITEFUNC_OUT_OF_MEMORY
[platform/upstream/curl.git] / src / tool_cb_hdr.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2011, 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 "setup.h"
23
24 #include <curl/curl.h>
25
26 #include "rawstr.h"
27
28 #define ENABLE_CURLX_PRINTF
29 /* use our own printf() functions */
30 #include "curlx.h"
31
32 #include "tool_cfgable.h"
33 #include "tool_cb_hdr.h"
34
35 #include "memdebug.h" /* keep this as LAST include */
36
37 static char *parse_filename(const char *ptr, size_t len);
38
39 /*
40 ** callback for CURLOPT_HEADERFUNCTION
41 */
42
43 size_t tool_header_cb(void *ptr, size_t size, size_t nmemb, void *userdata)
44 {
45   struct OutStruct *outs = userdata;
46   const char *str = ptr;
47   const size_t cb = size * nmemb;
48   const char *end = (char*)ptr + cb;
49
50   if(cb > 20 && checkprefix("Content-disposition:", str)) {
51     const char *p = str + 20;
52
53     /* look for the 'filename=' parameter
54        (encoded filenames (*=) are not supported) */
55     for(;;) {
56       char *filename;
57       size_t len;
58
59       while(*p && (p < end) && !ISALPHA(*p))
60         p++;
61       if(p > end - 9)
62         break;
63
64       if(memcmp(p, "filename=", 9)) {
65         /* no match, find next parameter */
66         while((p < end) && (*p != ';'))
67           p++;
68         continue;
69       }
70       p += 9;
71
72       /* this expression below typecasts 'cb' only to avoid
73          warning: signed and unsigned type in conditional expression
74       */
75       len = (ssize_t)cb - (p - str);
76       filename = parse_filename(p, len);
77       /* TODO: OOM handling - return (size_t)-1 ? */
78       if(filename) {
79         outs->filename = filename;
80         outs->alloc_filename = TRUE;
81         break;
82       }
83     }
84   }
85
86   return cb;
87 }
88
89 /*
90  * Copies a file name part and returns an ALLOCATED data buffer.
91  */
92 static char *parse_filename(const char *ptr, size_t len)
93 {
94   char *copy;
95   char *p;
96   char *q;
97   char  stop = '\0';
98
99   /* simple implementation of strndup() */
100   copy = malloc(len+1);
101   if(!copy)
102     return NULL;
103   memcpy(copy, ptr, len);
104   copy[len] = '\0';
105
106   p = copy;
107   if(*p == '\'' || *p == '"') {
108     /* store the starting quote */
109     stop = *p;
110     p++;
111   }
112   else
113     stop = ';';
114
115   /* if the filename contains a path, only use filename portion */
116   q = strrchr(copy, '/');
117   if(q) {
118     p = q + 1;
119     if(!*p) {
120       Curl_safefree(copy);
121       return NULL;
122     }
123   }
124
125   /* If the filename contains a backslash, only use filename portion. The idea
126      is that even systems that don't handle backslashes as path separators
127      probably want the path removed for convenience. */
128   q = strrchr(p, '\\');
129   if(q) {
130     p = q + 1;
131     if(!*p) {
132       Curl_safefree(copy);
133       return NULL;
134     }
135   }
136
137   /* scan for the end letter and stop there */
138   q = p;
139   while(*q) {
140     if(q[1] && (q[0] == '\\'))
141       q++;
142     else if(q[0] == stop)
143       break;
144     q++;
145   }
146   *q = '\0';
147
148   /* make sure the file name doesn't end in \r or \n */
149   q = strchr(p, '\r');
150   if(q)
151     *q = '\0';
152
153   q = strchr(p, '\n');
154   if(q)
155     *q = '\0';
156
157   if(copy != p)
158     memmove(copy, p, strlen(p) + 1);
159
160   /* in case we built curl debug enabled, we allow an evironment variable
161    * named CURL_TESTDIR to prefix the given file name to put it into a
162    * specific directory
163    */
164 #ifdef CURLDEBUG
165   {
166     char *tdir = curlx_getenv("CURL_TESTDIR");
167     if(tdir) {
168       char buffer[512]; /* suitably large */
169       snprintf(buffer, sizeof(buffer), "%s/%s", tdir, copy);
170       Curl_safefree(copy);
171       copy = strdup(buffer); /* clone the buffer, we don't use the libcurl
172                                 aprintf() or similar since we want to use the
173                                 same memory code as the "real" parse_filename
174                                 function */
175       curl_free(tdir);
176     }
177   }
178 #endif
179
180   return copy;
181 }
182