svn cleanup
[anytun.git] / Sockets / HttpdForm.cpp
blob1b1f689de683e3739698c1881c6580941483bce0
1 /** \file HttpdForm.cpp - read stdin, parse cgi input
2 **
3 ** Written: 1999-Feb-10 grymse@alhem.net
4 **/
6 /*
7 Copyright (C) 1999-2007 Anders Hedstrom
9 This library is made available under the terms of the GNU GPL.
11 If you would like to use this library in a closed-source application,
12 a separate license agreement is available. For information about
13 the closed-source license agreement for the C++ sockets library,
14 please visit http://www.alhem.net/Sockets/license.html and/or
15 email license@alhem.net.
17 This program is free software; you can redistribute it and/or
18 modify it under the terms of the GNU General Public License
19 as published by the Free Software Foundation; either version 2
20 of the License, or (at your option) any later version.
22 This program is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 GNU General Public License for more details.
27 You should have received a copy of the GNU General Public License
28 along with this program; if not, write to the Free Software
29 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 #ifdef _MSC_VER
32 #pragma warning(disable:4786)
33 #endif
34 #include "socket_include.h"
35 #include "Parse.h"
36 #include "IFile.h"
37 #include "HttpdForm.h"
39 #ifdef SOCKETS_NAMESPACE
40 namespace SOCKETS_NAMESPACE {
41 #endif
43 #define TMPSIZE 10000
46 HttpdForm::HttpdForm(IFile *infil, const std::string& content_type, size_t content_length) : raw(false)
48 CGI *cgi = NULL;
49 size_t extra = 2;
50 char name[TMPSIZE];
52 m_current = m_cgi.end();
53 *name = 0;
55 if (content_type.size() >= 19 && content_type.substr(0, 19) == "multipart/form-data")
57 Parse pa(content_type,";=");
58 char *tempcmp = NULL;
59 size_t tc = 0;
60 size_t l = 0;
61 std::string str = pa.getword();
62 m_strBoundary = "";
63 while (str.size())
65 if (!strcmp(str.c_str(),"boundary"))
67 m_strBoundary = pa.getword();
68 l = m_strBoundary.size();
69 tempcmp = new char[l + extra];
72 str = pa.getword();
74 if (m_strBoundary.size())
76 std::string content_type;
77 std::string current_name;
78 std::string current_filename;
79 char *slask = new char[TMPSIZE];
80 infil -> fgets(slask, TMPSIZE);
81 while (!infil -> eof())
83 while (strlen(slask) && (slask[strlen(slask) - 1] == 13 || slask[strlen(slask) - 1] == 10))
85 slask[strlen(slask) - 1] = 0;
87 content_type = "";
88 current_name = "";
89 current_filename = "";
90 if ((strstr(slask,m_strBoundary.c_str()) || strstr(m_strBoundary.c_str(),slask)) && strcmp(slask, m_strBoundary.c_str()))
92 m_strBoundary = slask;
93 l = m_strBoundary.size();
94 delete[] tempcmp;
95 tempcmp = new char[l + extra];
97 if (!strcmp(slask, m_strBoundary.c_str()))
99 // Get headers until empty line
100 infil -> fgets(slask, TMPSIZE);
101 while (strlen(slask) && (slask[strlen(slask) - 1] == 13 || slask[strlen(slask) - 1] == 10))
103 slask[strlen(slask) - 1] = 0;
105 while (!infil -> eof() && *slask)
107 Parse pa(slask,";");
108 std::string h = pa.getword();
109 if (!strcasecmp(h.c_str(),"Content-type:"))
111 content_type = pa.getword();
113 else
114 if (!strcasecmp(h.c_str(),"Content-Disposition:"))
116 h = pa.getword();
117 if (!strcmp(h.c_str(),"form-data"))
119 pa.EnableQuote(true);
120 h = pa.getword();
121 while (h.size())
123 Parse pa2(slask,"=");
124 std::string name = pa2.getword();
125 std::string h = pa2.getrest();
126 if (!strcmp(name.c_str(),"name"))
128 if (h.size() && h[0] == '"')
130 current_name = h.substr(1, h.size() - 2);
132 else
134 current_name = h;
137 else
138 if (!strcmp(name.c_str(),"filename"))
140 if (h.size() && h[0] == '"')
142 current_filename = h.substr(1, h.size() - 2);
144 else
146 current_filename = h;
148 size_t x = 0;
149 for (size_t i = 0; i < current_filename.size(); i++)
151 if (current_filename[i] == '/' || current_filename[i] == '\\')
152 x = i + 1;
154 if (x)
156 current_filename = current_filename.substr(x);
159 h = pa.getword();
163 // get next header value
164 infil -> fgets(slask, TMPSIZE);
165 while (strlen(slask) && (slask[strlen(slask) - 1] == 13 || slask[strlen(slask) - 1] == 10))
167 slask[strlen(slask) - 1] = 0;
170 // Read content, save...?
171 if (!current_filename.size()) // not a file
173 std::string val;
174 infil -> fgets(slask, TMPSIZE);
175 while (!infil -> eof() && strncmp(slask,m_strBoundary.c_str(),m_strBoundary.size() ))
177 val += slask;
178 infil -> fgets(slask, TMPSIZE);
180 // remove trailing cr/linefeed
181 while (val.size() && (val[val.size() - 1] == 13 || val[val.size() - 1] == 10))
183 val = val.substr(0,val.size() - 1);
185 cgi = new CGI(current_name, val);
186 m_cgi.push_back(cgi);
188 else // current_filename.size() > 0
190 // read until m_strBoundary...
191 FILE *fil;
192 int out = 0;
193 char c;
194 char fn[2000]; // where post'd file will be saved
195 #ifdef _WIN32
197 char tmp_path[2000];
198 ::GetTempPathA(2000, tmp_path);
199 if (tmp_path[strlen(tmp_path) - 1] != '\\')
201 strcat(tmp_path, "\\");
203 sprintf(fn,"%s%s",tmp_path,current_filename.c_str());
205 #else
206 sprintf(fn,"/tmp/%s",current_filename.c_str());
207 #endif
208 if ((fil = fopen(fn, "wb")) != NULL)
210 infil -> fread(&c,1,1);
211 while (!infil -> eof())
213 if (out)
215 fwrite(&tempcmp[tc],1,1,fil);
217 tempcmp[tc] = c;
218 tc++;
219 if (tc >= l + extra)
221 tc = 0;
222 out = 1;
224 if (tc)
226 if (!strncmp(tempcmp + tc + extra, m_strBoundary.c_str(), l - tc) &&
227 !strncmp(tempcmp, m_strBoundary.c_str() + l - tc, tc))
229 break;
232 else
234 if (!strncmp(tempcmp + extra, m_strBoundary.c_str(), l))
236 break;
239 infil -> fread(&c,1,1);
241 fclose(fil);
243 cgi = new CGI(current_name,fn,fn);
244 m_cgi.push_back(cgi);
246 strcpy(slask, m_strBoundary.c_str());
247 infil -> fgets(slask + strlen(slask), TMPSIZE); // next line
249 else
251 // couldn't open file
252 break;
256 else
258 // Probably '<m_strBoundary>--'
259 break;
261 } // while (!infil -> eof())
262 delete[] slask;
263 } // if (m_strBoundary)
264 if (tempcmp)
266 delete[] tempcmp;
269 else
270 if (strstr(content_type.c_str(), "x-www-form-urlencoded"))
272 bool got_name = false; // tnx to FatherNitwit
273 int i = 0;
274 int cl = (int)content_length;
275 char c,chigh,clow;
276 char *slask = new char[TMPSIZE];
277 m_current = m_cgi.end();
279 *name = 0;
281 infil -> fread(&c,1,1);
282 cl--;
283 while (cl >= 0 && !infil -> eof())
285 switch (c)
287 case '=': /* end of name */
288 slask[i] = 0;
289 i = 0;
290 strcpy(name,slask);
291 got_name = true;
292 break;
293 case '&': /* end of value */
294 slask[i] = 0;
295 i = 0;
296 if (got_name)
298 cgi = new CGI(name,slask);
299 got_name = false;
301 else
303 cgi = new CGI(slask, "");
305 m_cgi.push_back(cgi);
306 break;
307 case '+': /* space */
308 slask[i++] = ' ';
309 break;
310 case '%': /* hex value */
311 infil -> fread(&chigh,1,1);
312 cl--;
313 chigh -= 48 + (chigh > '9' ? 7 : 0) + (chigh >= 'a' ? 32 : 0);
314 infil -> fread(&clow,1,1);
315 cl--;
316 clow -= 48 + (clow > '9' ? 7 : 0) + (clow >= 'a' ? 32 : 0);
317 slask[i++] = (char)(chigh * 16 + clow);
318 break;
319 default: /* just another char */
320 slask[i++] = c;
321 break;
324 if (cl > 0)
326 infil -> fread(&c,1,1);
328 cl--;
330 slask[i] = 0;
331 i = 0;
332 if (got_name)
334 cgi = new CGI(name,slask);
336 else
338 cgi = new CGI(slask, "");
340 m_cgi.push_back(cgi);
341 delete[] slask;
346 // HttpdForm(buffer,l) -- request_method GET
348 HttpdForm::HttpdForm(const std::string& buffer,size_t l) : raw(false)
350 CGI *cgi = NULL;
351 char *slask = new char[TMPSIZE];
352 char *name = new char[TMPSIZE];
353 int i = 0;
354 char c,chigh,clow;
355 size_t ptr = 0;
356 bool got_name = false;
358 m_current = m_cgi.end();
360 *name = 0;
362 ptr = 0;
363 while (ptr < l)
365 c = buffer[ptr++];
366 switch (c)
368 case '=': /* end of name */
369 slask[i] = 0;
370 i = 0;
371 strcpy(name,slask);
372 got_name = true;
373 break;
374 case '&': /* end of value */
375 slask[i] = 0;
376 i = 0;
377 if (got_name)
379 cgi = new CGI(name,slask);
380 got_name = false;
382 else
384 cgi = new CGI(slask, "");
386 m_cgi.push_back(cgi);
387 break;
388 case '+': /* space */
389 slask[i++] = ' ';
390 break;
391 case '%': /* hex value */
392 chigh = buffer[ptr++];
393 chigh -= 48 + (chigh > '9' ? 7 : 0) + (chigh >= 'a' ? 32 : 0);
394 clow = buffer[ptr++];
395 clow -= 48 + (clow > '9' ? 7 : 0) + (clow >= 'a' ? 32 : 0);
396 slask[i++] = (char)(chigh * 16 + clow);
397 break;
398 default: /* just another char */
399 slask[i++] = c;
400 break;
403 slask[i] = 0;
404 i = 0;
405 if (got_name)
407 cgi = new CGI(name,slask);
409 else
411 cgi = new CGI(slask, "");
413 m_cgi.push_back(cgi);
414 delete[] slask;
415 delete[] name;
419 HttpdForm::~HttpdForm()
421 CGI *cgi = NULL; //,*tmp;
423 for (cgi_v::iterator it = m_cgi.begin(); it != m_cgi.end(); it++)
425 cgi = *it;
426 delete cgi;
431 void HttpdForm::EnableRaw(bool b)
433 raw = b;
437 void HttpdForm::strcpyval(std::string& v,const char *value) const
439 v = "";
440 for (size_t i = 0; i < strlen(value); i++)
442 if (value[i] == '<')
444 v += "&lt;";
446 else
447 if (value[i] == '>')
449 v += "&gt;";
451 else
452 if (value[i] == '&')
454 v += "&amp;";
456 else
458 v += value[i];
464 bool HttpdForm::getfirst(std::string& n) const
466 m_current = m_cgi.begin();
467 return getnext(n);
471 bool HttpdForm::getnext(std::string& n) const
473 if (m_current != m_cgi.end() )
475 CGI *current = *m_current;
476 n = current -> name;
477 m_current++;
478 return true;
480 else
482 n = "";
484 return false;
488 bool HttpdForm::getfirst(std::string& n,std::string& v) const
490 m_current = m_cgi.begin();
491 return getnext(n,v);
495 bool HttpdForm::getnext(std::string& n,std::string& v) const
497 if (m_current != m_cgi.end() )
499 CGI *current = *m_current;
500 n = current -> name;
501 if (raw)
503 v = current -> value;
505 else
507 strcpyval(v,current -> value.c_str());
509 m_current++;
510 return true;
512 else
514 n = "";
516 return false;
520 int HttpdForm::getvalue(const std::string& n,std::string& v) const
522 CGI *cgi = NULL;
523 int r = 0;
525 for (cgi_v::const_iterator it = m_cgi.begin(); it != m_cgi.end(); it++)
527 cgi = *it;
528 if (cgi -> name == n)
529 break;
530 cgi = NULL;
532 if (cgi)
534 if (raw)
536 v = cgi -> value;
538 else
540 strcpyval(v,cgi -> value.c_str());
542 r++;
544 else
546 v = "";
549 return r;
553 std::string HttpdForm::getvalue(const std::string& n) const
555 for (cgi_v::const_iterator it = m_cgi.begin(); it != m_cgi.end(); it++)
557 CGI *cgi = *it;
558 if (cgi -> name == n)
560 return cgi -> value;
563 return "";
567 size_t HttpdForm::getlength(const std::string& n) const
569 CGI *cgi = NULL;
570 size_t l;
572 for (cgi_v::const_iterator it = m_cgi.begin(); it != m_cgi.end(); it++)
574 cgi = *it;
575 if (cgi -> name == n)
576 break;
577 cgi = NULL;
579 l = cgi ? cgi -> value.size() : 0;
580 if (cgi && !raw)
582 for (size_t i = 0; i < cgi -> value.size(); i++)
584 switch (cgi -> value[i])
586 case '<': // &lt;
587 case '>': // &gt;
588 l += 4;
589 break;
590 case '&': // &amp;
591 l += 5;
592 break;
596 return l;
600 HttpdForm::cgi_v& HttpdForm::getbase()
602 return m_cgi;
606 const std::string& HttpdForm::GetBoundary() const
608 return m_strBoundary;
612 #ifdef SOCKETS_NAMESPACE
614 #endif