diff options
-rw-r--r-- | lib/HttpServ.cc | 228 |
1 files changed, 218 insertions, 10 deletions
diff --git a/lib/HttpServ.cc b/lib/HttpServ.cc index 23f45d4..57afd20 100644 --- a/lib/HttpServ.cc +++ b/lib/HttpServ.cc @@ -17,7 +17,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* $Id: HttpServ.cc,v 1.58 2007-09-28 09:23:36 pixel Exp $ */ +/* $Id: HttpServ.cc,v 1.59 2007-10-12 13:07:19 pixel Exp $ */ + +#include <vector> #ifdef HAVE_CONFIG_H #include "config.h" @@ -35,12 +37,57 @@ #include "HashFunction.h" #include "gettext.h" +#define MAXLEN 4*1024*1024 + +/* + stuff we should support... + + Etags: + Server: ETag: "27b42a-134-46cece08" + Client: If-None-Match: "27b42a-146-46cecd32" + + Last-Modified: + Server: Last-Modified: Fri, 24 Aug 2007 12:24:40 GMT + Client: If-Modified-Since: Fri, 24 Aug 2007 12:21:06 GMT + + Multipart stuff: + +----8<-----Example-------8<-------- +Content-Type: multipart/form-data; boundary=---------------------------163944935918044553841983937859 +Content-Length: 377 + +-----------------------------163944935918044553841983937859 +Content-Disposition: form-data; name="textline" + + +-----------------------------163944935918044553841983937859 +Content-Disposition: form-data; name="datafile"; filename="tst-user-agent.txt" +Content-Type: text/plain + +User-Agent: CFNetwork/129.20 + +-----------------------------163944935918044553841983937859-- +----8<-----Example-------8<-------- + +*/ + + + String endhl = "\r\n", endnl = "\n"; +struct multipart_file { + multipart_file(Buffer * _file, const String & _type, const String & _filename, const String & _varname) : file(_file), type(_type), filename(_filename), varname(_varname) { } + ~multipart_file() { } + Buffer * file; + String type, filename, varname; +}; + +typedef std::vector<struct multipart_file> multipart_files; + class ProcessRequest : public Task { public: ProcessRequest(Action * action, const Socket & out, const String & server_name, int server_port, const String & root = "/bin/start"); - virtual ~ProcessRequest() {} + virtual ~ProcessRequest(); virtual String GetName(); protected: virtual int Do() throw (GeneralException); @@ -49,6 +96,7 @@ class ProcessRequest : public Task { String UnMangle(const String &, int p = 0); bool ParseUri(String &, String &, String &, Handle *); void ParseVars(Handle *, int); + void ParseMultipart(Handle *, int); void ShowError(Handle *); void SendHeads(Handle *, const String &, const String & = "", time_t = -1); void SendRedirect(Handle *); @@ -61,10 +109,12 @@ class ProcessRequest : public Task { Action * p; Socket s; Domain * d; - - String name, host, gvars, login, password, root; + + multipart_files m_files; + + String name, host, gvars, login, password, root, boundary; Variables * Vars, * Heads; - bool bad, hasvars, post; + bool bad, hasvars, post, multipart, content_type; HttpResponse response; }; @@ -73,6 +123,14 @@ ProcessRequest::ProcessRequest(Action * ap, const Socket & as, const String & an SetBurst(); } +ProcessRequest::~ProcessRequest() { + std::vector<struct multipart_file>::iterator i; + + for (i = m_files.begin(); i != m_files.end(); i++) { + delete i->file; + } +} + String ProcessRequest::GetName() { return _("Processing HTTP request"); } @@ -100,6 +158,7 @@ int ProcessRequest::Do() throw(GeneralException) { Vars = new Variables(); len = -1; + content_type = false; do { int p; b >> t; @@ -107,6 +166,8 @@ int ProcessRequest::Do() throw(GeneralException) { if ((t.strstr("Content-Length: ") == 0) || (t.strstr("Content-length: ") == 0)) { // std::cerr << "Saw 'Content-Lenght:', reading length from '" << t.extract(16) << "'\n"; len = t.extract(16).to_int(); + if (len > MAXLEN) + len = -1; } if (t.strstr("Host: ") == 0) { host = t.extract(6); @@ -125,6 +186,16 @@ int ProcessRequest::Do() throw(GeneralException) { free(credentials); } + if (t.strstr("Content-Type: application/x-www-form-urlencoded") == 0) { + // basic post method + multipart = false; + content_type = true; + } + if (t.strstr("Content-Type: multipart/form-data; boundary=") == 0) { + multipart = true; + content_type = true; + boundary = "--" + t.extract(44); + } if ((p = t.strchr(':')) >= 0) { String s = t.extract(0, p - 1); @@ -149,14 +220,18 @@ int ProcessRequest::Do() throw(GeneralException) { // Les variables seront initialisées ici. hasvars = true; } + + if (!content_type) { + bad = true; + } } current = 2; - if (hasvars && (len)) { + if (hasvars && len) { c = new CopyJob(&s, &b, len); WaitFor(c); Suspend(); - } else { + } else { c = 0; } @@ -166,9 +241,13 @@ int ProcessRequest::Do() throw(GeneralException) { b2 << gvars; ParseVars(&b2, gvars.strlen()); } - if (hasvars) { - if (c) delete c; - ParseVars(&b, len); + if (hasvars && len) { + delete c; + if (!multipart) { + ParseVars(&b, len); + } else { + ParseMultipart(&b, len); + } } std::cerr << " Domain = '" << domain << "' - File = '" << file << "'\n"; @@ -274,6 +353,133 @@ int ProcessRequest::Do() throw(GeneralException) { return TASK_DONE; } +void ProcessRequest::ParseMultipart(Handle * s, int len) { + String t, crboundary, k, v, disposition, type; + char redo[256], r, tmp[4]; + int p, i, rl; + bool done = false, in_headers = true, is_file = false; + Buffer * out = 0; + std::vector<struct multipart_file>::iterator mf_p; + Variables * dispos_headers; + + crboundary = "\r\n" + boundary; + + redo[0] = p = 0; + i = 1; + while (i < crboundary.strlen()) { + if (crboundary[i] == crboundary[p]) { + redo[i++] = ++p; + } else if (p > 0) { + p = redo[p - 1]; + } else { + redo[i++] = 0; + } + } + + p = 0; + (*s) >> t; + if (t != boundary) { + return; + } + while (!done) { + if (in_headers) { + (*s) >> t; + if (t != "") { + // Content-Disposition: form-data; name="datafile"; filename="tst-user-agent.txt" + // Content-Type: text/plain + if (t.strstr("Content-Disposition: form-data; ") == 0) { + disposition = t.extract(32); + dispos_headers = new Variables(); + // **** + } else if (t.strstr("Content-Type: ") == 0) { + type = t.extract(14); + } else { + printm(M_WARNING, "Unknown header in multipart chunk: " + t + "\n"); + } + } else { + in_headers = false; + if ((type != "") && ((*dispos_headers)["filename"] != "")) { + is_file = true; + out = new Buffer(); + } else { + k = (*dispos_headers)["name"]; + } + } + } else { + rl = 0; + + r = s->readU8(); + if (crboundary[p] == r) { + p++; + rl = 1; + } else { + for (i = 0; i <= p; i++) { + if (is_file) { + out->writeU8(crboundary[i]); + } else { + v += crboundary[i]; + } + } + if (p > 0) + p = redo[p - 1]; + } + + if (p == crboundary.strlen()) { + p = 0; + tmp[0] = s->readU8(); + tmp[1] = s->readU8(); + + if ((t[0] == 13) && (t[1] == 10)) { + in_headers = true; + + if (is_file) { + m_files.push_back(multipart_file(out, type, (*dispos_headers)["filename"], (*dispos_headers)["name"])); + out = 0; + } else { + Vars->Add(k + "=" + v); + } + + k = ""; + v = ""; + type = ""; + delete dispos_headers; + } else if ((tmp[0] == '-') && (tmp[1] == '-')) { + tmp[2] = s->readU8(); + tmp[3] = s->readU8(); + if ((tmp[2] == 13) && (tmp[3] == 10)) { + // end of streams + + if (is_file) { + m_files.push_back(multipart_file(out, type, (*dispos_headers)["filename"], (*dispos_headers)["name"])); + out = 0; + } else { + Vars->Add(k + "=" + v); + } + return; + } else { + rl = 4; + } + } else { + rl = 2; + } + } + + for (i = 0; i < rl; i++) { + if (is_file) { + out->writeU8(r); + } else { + v += r; + } + + r = tmp[0]; + tmp[0] = tmp[1]; + tmp[1] = tmp[2]; + tmp[2] = tmp[3]; + } + } + } +} + void ProcessRequest::ParseVars(Handle * s, int len) { String t, v; char conv[3], l; @@ -290,6 +496,8 @@ void ProcessRequest::ParseVars(Handle * s, int len) { // Les variables sont sous la forme 'var1=val1&var2=val2&val3=var3'. Donc le nombre d'occurences // du caractère '=' indique le nombre de variables. + + // WRONG! WRONG! nbvars = t.strchrcnt('='); for (int i = 0; i < nbvars; i++) { |