1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161 |
- /*##############################################################################
- Copyright (C) 2011 HPCC Systems.
- All rights reserved. This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- ############################################################################## */
- #pragma warning(disable : 4786)
- #ifdef WIN32
- #ifdef ESPHTTP_EXPORTS
- #define esp_http_decl __declspec(dllexport)
- #endif
- #endif
- //Jlib
- #include "jliball.hpp"
- //ESP Binidings
- #include "http/platform/httptransport.ipp"
- #include "bindutil.hpp"
- IEspHttpException* createEspHttpException(int code, const char *_msg, const char* _httpstatus)
- {
- return new CEspHttpException(code, _msg, _httpstatus);
- }
- bool httpContentFromFile(const char *filepath, StringBuffer &mimetype, MemoryBuffer &fileContents)
- {
- StringBuffer strfile(filepath);
- if (!checkFileExists(strfile.str()))
- if (!checkFileExists(strfile.toUpperCase().str()))
- if (!checkFileExists(strfile.toLowerCase().str()))
- return false;
- Owned<IFile> file = createIFile(strfile.str());
- if (file && file->isFile())
- {
- Owned<IFileIO> io = file->open(IFOread);
- if (io)
- {
- size32_t filesize = io->size();
- io->read(0, filesize, fileContents.reserveTruncate(filesize));
- mimetype.clear();
- const char *ext = strrchr(filepath, '.');
- if (ext)
- {
- ext++;
- if (!stricmp(ext, "html") || !stricmp(ext, "htm"))
- mimetype.append("text/html");
- else if (!stricmp(ext, "js"))
- mimetype.append("text/javascript");
- else if (!stricmp(ext, "jpeg") || !stricmp(ext, "jpg"))
- mimetype.append("image/gif");
- else if (!stricmp(ext, "gif"))
- mimetype.append("image/gif");
- else if (!stricmp(ext, "png"))
- mimetype.append("image/png");
- else if (!stricmp(ext, "xml") || !stricmp(ext, "xsl"))
- mimetype.append("text/xml");
- else if (!stricmp(ext, "txt") || !stricmp(ext, "text"))
- mimetype.append("text/plain");
- else if (!stricmp(ext, "zip"))
- mimetype.append("application/zip");
- else if (!stricmp(ext, "pdf"))
- mimetype.append("application/pdf");
- else if (!stricmp(ext, "pdf"))
- mimetype.append("application/pdf");
- else if (!stricmp(ext, "xpi"))
- mimetype.append("application/x-xpinstall");
- else if (!stricmp(ext, "exe") || !stricmp(ext, "class"))
- mimetype.append("application/octet-stream");
- else if (!stricmp(ext, "xsl") || !stricmp(ext, "xslt"))
- mimetype.append("text/xml");
- else if (!stricmp(ext, "css"))
- mimetype.append("text/css");
- else if (!stricmp(ext, "svg"))
- mimetype.append("image/svg+xml");
- }
-
- if (!mimetype.length())
- mimetype.append("application/octet-stream");
- return true;
- }
- }
-
- return false;
- }
- /***************************************************************************
- CHttpMessage Implementation
- This class implements common functions shared by both CHttpRequest
- and CHttpResponse
- ****************************************************************************/
- CHttpMessage::CHttpMessage(ISocket& socket) : m_socket(socket)
- {
- m_bufferedsocket.setown(createBufferedSocket(&socket));
- m_content_length = -1;
- m_content_length64 = -1;
- m_port = 80;
- m_paramCount = 0;
- m_attachCount = 0;
- m_supportClientXslt=-1;
- m_isForm = false;
- };
- CHttpMessage::~CHttpMessage()
- {
- try
- {
- m_bufferedsocket.clear();
- m_context.clear();
- m_queryparams.clear();
- m_content_stream.clear();
- }
- catch(...)
- {
- ERRLOG("In CHttpMessage::~CHttpMessage() -- Unknown exception.");
- }
- };
- int CHttpMessage::parseOneHeader(char* oneline)
- {
- if (getEspLogLevel()>LogNormal)
- DBGLOG("%s", oneline);
- if(!oneline)
- return -1;
- char* name = oneline;
- while(*name == ' ')
- name++;
- char* end = name;
- while(*end != '\0' && *end != ':')
- end++;
- char* value;
- if (*end == ':')
- {
- *end = '\0';
- value = end + 1;
- }
- else
- value = end;
- while(*value == ' ')
- value++;
-
- if(!stricmp(name, "Content-Type"))
- {
- m_content_type.set(value);
- }
- else if(!stricmp(name, "Content-Length"))
- {
- if(value != NULL)
- {
- m_content_length = atoi(value);
- m_content_length64 = atoi64_l(value,strlen(value));
- }
- }
- else if(!stricmp(name, "Host"))
- {
- if(value != NULL)
- {
- char* colon = strchr(value, ':');
- if(colon != NULL)
- {
- *colon = '\0';
- char* port = colon + 1;
- if(port != NULL)
- {
- m_port = atoi(port);
- }
- }
- m_host.set(value);
- }
- }
- else if(!stricmp(name, "Set-Cookie") || !stricmp(name, "Cookie"))
- {
- parseCookieHeader(value);
- }
- else
- {
- addHeader(name, value); //Insert into headers hashtable
- }
- return 0;
- }
- bool CHttpMessage::supportClientXslt()
- {
- if (m_supportClientXslt==-1)
- {
- bool ie6=false;
- bool moz5=false;
- bool opera=false;
- bool ff=false;
- StringBuffer uastr;
- getHeader("User-Agent", uastr);
-
- char *uagent=strdup(uastr.str());
- char *saveptr;
- char *token = strtok_r(uagent, "();", &saveptr);
- while(token)
- {
- while (*token==' ') token++;
- if (!strnicmp(token, "msie", 4))
- ie6=(token[5]>='6');
- else if (!strnicmp(token, "mozilla", 7))
- moz5=(token[8]>='5');
- else if (!strnicmp(token, "opera", 5))
- opera=true;
- else if (!strnicmp(token, "firefox", 7))
- ff=true;
- token = strtok_r( NULL, "();" , &saveptr);
- }
- free(uagent);
- m_supportClientXslt=(ff || moz5 || (ie6 && !opera)) ? 1 : 0;
- }
- return m_supportClientXslt==1;
- }
- /*
- void CHttpMessage::addRawXMLParameter(const char* path, IPropertyTree* tree)
- {
- const char* name = tree->queryName();
- if (stricmp(name, "RawArray")==0)
- {
- Owned<IPropertyTreeIterator> row = tree->getElements("Item");
- int items = 0;
- for (row->first(); row->isValid(); row->next())
- {
- IPropertyTree* pRow = &row->query();
- StringBuffer newpath(path);
- newpath.appendf(".%d",items);
- const char* value = pRow->queryProp(NULL);
- if (value)
- {
- if (*value)
- m_queryparams->setProp(newpath, value);
- }
- else
- {
- Owned<IPropertyTreeIterator> field = pRow->getElements("*");
- int baseLen = newpath.length();
- for (field->first(); field->isValid(); field->next())
- {
- newpath.appendf(".%s", field->query().queryName());
- addRawXMLParameter(newpath, &field->query());
- newpath.setLength(baseLen);
- }
- }
- items++;
- }
- if (items>0)
- {
- StringBuffer newpath(path),v;
- newpath.append(".itemcount");
- v.append(items);
- m_queryparams->setProp(newpath, v);
- m_paramCount++;
- }
- }
- else
- {
- const char* value = tree->queryProp(NULL);
- if (value)
- {
- if (*value)
- m_queryparams->setProp(path, value);
- }
- else // subtree
- {
- Owned<IPropertyTreeIterator> field = tree->getElements("*");
- for (field->first(); field->isValid(); field->next())
- {
- const char* fieldName = field->query().queryName();
- StringBuffer newpath(path);
- if (stricmp(fieldName, "RawArray")!=0)
- newpath.appendf(".%s",field->query().queryName());
- addRawXMLParameter(newpath, &field->query());
- }
- }
- }
- }
- void CHttpMessage::addRawXMLParameter(const char* path, const char *value)
- {
- Owned<IPropertyTree> tree;
- try
- {
- tree.setown(createPTreeFromXMLString(value));
- }
- catch(IException* e)
- {
- StringBuffer msg;
- e->errorMessage(msg);
- ERRLOG("Error parsing struct array: %s", msg.str());
- return;
- }
- addRawXMLParameter(path, tree);
- }
- */
- void CHttpMessage::addParameter(const char* paramname, const char *value)
- {
- if (!m_queryparams)
- m_queryparams.setown(createProperties(false));
- if (strcmp(paramname,"form")==0)
- m_isForm = true;
- if (!m_isForm)
- {
- // remove the leading '.'
- if (*paramname=='.')
- paramname++;
- }
- m_queryparams->setProp(paramname, value);
- m_paramCount++;
- }
- StringBuffer& CHttpMessage::getParameter(const char* paramname, StringBuffer& paramval)
- {
- if (m_queryparams)
- {
- const char *value = m_queryparams->queryProp(paramname);
- if (value)
- paramval.append(value);
- }
- return paramval;
- }
- void CHttpMessage::addAttachment(const char* name, StringBuffer& value)
- {
- if(name != NULL)
- {
- m_attachments.setValue(name, value);
- m_attachCount++;
- }
- }
- StringBuffer& CHttpMessage::getAttachment(const char* name, StringBuffer& attachment)
- {
- StringBuffer *value = m_attachments.getValue(name);
- if (value)
- {
- attachment.append(value->length(), value->str());
- }
- return attachment;
- }
- StringBuffer& CHttpMessage::getParamStr(StringBuffer& ret)
- {
- return ret.append(m_paramstr);
- }
- IProperties *CHttpMessage::queryParameters()
- {
- if (!m_queryparams)
- m_queryparams.setown(createProperties(false));
- return m_queryparams.get();
- }
- IProperties *CHttpMessage::getParameters()
- {
- if (!m_queryparams)
- m_queryparams.setown(createProperties(false));
- return m_queryparams.getLink();
- }
- int CHttpMessage::processHeaders(IMultiException *me)
- {
- return 0;
- }
- int CHttpMessage::readContent()
- {
- char buf[1024 + 1];
- int buflen = 1024;
- if(m_content_length > 0)
- {
- int totallen = m_content_length;
- if(buflen > totallen)
- buflen = totallen;
- int readlen = 0;
- for(;;)
- {
- readlen = m_bufferedsocket->read(buf, buflen);
- if(readlen < 0)
- {
- DBGLOG(">> Socket timed out because of incorrect Content-Length passed in from the other side");
- break;
- }
- if(readlen == 0)
- break;
- buf[readlen] = 0;
- m_content.append(readlen, buf);
- totallen -= readlen;
- if(totallen <= 0)
- break;
- if(buflen > totallen)
- buflen = totallen;
- }
-
- return 0;
- }
- return 0;
- }
- int CHttpMessage::readContentTillSocketClosed()
- {
- const int buflen = 1024;
- char buf[buflen + 1];
- StringBuffer headerValue;
- getHeader("Transfer-Encoding", headerValue);
- if (!stricmp(headerValue.str(), "chunked"))//Transfer-Encoding: chunked
- {
- for(;;)
- {
- int readlen = m_bufferedsocket->readline(buf, buflen, NULL);
- if(readlen <= 0)
- break;
- buf[readlen] = 0;
- int chunkSize;
- sscanf(buf, "%x", &chunkSize);
- if (chunkSize<=0)
- break;
- while (chunkSize > 0)
- {
- const int len = min(chunkSize, buflen);
- readlen = m_bufferedsocket->read(buf, len);
- if(readlen <= 0)
- break;
- chunkSize -= readlen;
- m_content.append(readlen, buf);
- }
- if (m_bufferedsocket->read(buf, 2) <= 0)//CR/LF
- break;
- }
- }
- else
- {
- for(;;)
- {
- int readlen = m_bufferedsocket->read(buf, buflen);
- if(readlen <= 0)
- break;
- buf[readlen] = 0;
- m_content.append(readlen, buf);
- }
- }
- return 0;
- }
- int CHttpMessage::receive(bool alwaysReadContent, IMultiException *me)
- {
- if (processHeaders(me)==-1)
- return -1;
- if (getEspLogLevel()>LogNormal)
- DBGLOG("Headers processed! content_length = %d", m_content_length);
-
- if (isUpload())
- return 0;
- m_context->addTraceSummaryValue("contLen", m_content_length);
- if(m_content_length > 0)
- {
- readContent();
- if (getEspLogLevel()>LogNormal)
- DBGLOG("length of content read = %d", m_content.length());
- }
- else if (alwaysReadContent && m_content_length == -1)
- {
- //HTTP protocol does not require a content length: read until socket closed
- readContentTillSocketClosed();
- if (getEspLogLevel()>LogNormal)
- DBGLOG("length of content read = %d", m_content.length());
- }
-
- if (getEspLogRequests() || getEspLogLevel()>LogNormal)
- {
- if(isTextMessage())
- DBGLOG("received HTTP content:\n%s", m_content.str());
- }
- return 0;
- }
- StringBuffer& CHttpMessage::getContent(StringBuffer& content)
- {
- content.append(m_content.length(), m_content.str());
- return content;
- }
- void CHttpMessage::setContent(const char* content)
- {
- m_content.clear();
- m_content.append(content);
- m_content_length = strlen(content);
- }
- void CHttpMessage::setContent(unsigned len, const char* content)
- {
- m_content.clear();
- m_content.append(len, content);
- m_content_length = len;
- }
- void CHttpMessage::setownContent(char* content)
- {
- size32_t len=strlen(content);
- m_content.setBuffer(len+1, content, len);
- m_content_length = len;
- }
- void CHttpMessage::setownContent(unsigned len, char* content)
- {
- m_content.setBuffer(len+1, content, len);
- m_content_length = len;
- }
- void CHttpMessage::setContent(IFileIOStream* stream)
- {
- if(stream != NULL)
- {
- m_content.clear();
- m_content_length = stream->size();
- m_content_length64 = stream->size();
- m_content_stream.setown(stream);
- }
- }
- /*
- void CHttpMessage::appendContent(const char* content)
- {
- m_content.append(content);
- m_content_length += strlen(content);
- }
- */
- StringBuffer& CHttpMessage::getContentType(StringBuffer& contenttype)
- {
- contenttype.append(m_content_type);
- return contenttype;
- }
- void CHttpMessage::setContentType(const char* contenttype)
- {
- m_content_type.set(contenttype);
- }
- void CHttpMessage::setVersion(const char* version)
- {
- m_version.set(version);
- }
- int CHttpMessage::parseFirstLine(char* oneline)
- {
- return 0;
- }
- void CHttpMessage::parseCookieHeader(char* cookiestr)
- {
- }
- StringBuffer& CHttpMessage::constructHeaderBuffer(StringBuffer& headerbuf, bool inclLen)
- {
- return headerbuf;
- }
- int CHttpMessage::send()
- {
- StringBuffer headers;
- constructHeaderBuffer(headers, true);
-
- int retcode = 0;
- // If m_content is empty but m_content_stream is set, the stream will not be logged here.
- if (getEspLogResponses() || getEspLogLevel(queryContext())>LogNormal)
- {
- DBGLOG("Sending out HTTP message:\n%s", headers.str());
- if(m_content_length > 0 && m_content.length() > 0)
- {
- if(isTextMessage())
- DBGLOG("sent HTTP Content:\n%s", m_content.str());
- else
- DBGLOG("sent HTTP <non-text content>");
- }
- }
- try
- {
- m_socket.write(headers.str(), headers.length());
- if(m_content_length > 0 && m_content.length() > 0)
- m_socket.write(m_content.str(), m_content.length());
- }
- catch (IException *e)
- {
- StringBuffer estr;
- DBGLOG("In CHttpMessage::send(%d) -- Exception(%d, %s) writing to socket(%d).", __LINE__, e->errorCode(), e->errorMessage(estr).str(), m_socket.OShandle());
- e->Release();
- return -1;
- }
- catch(...)
- {
- ERRLOG("In CHttpMessage::send(%d) -- Unknown exception writing to socket(%d).", __LINE__, m_socket.OShandle());
- return -1;
- }
- // When m_content is empty but the stream was set, read content from the stream.
- if(((m_content_length > 0 && m_content.length() == 0) || (m_content_length64 > 0)) && m_content_stream.get() != NULL)
- {
- //Read the file and send out 20K at a time.
- __int64 content_length = m_content_length;
- if ((m_content_length64 > 0) && (content_length != m_content_length64))
- content_length = m_content_length64;
- int buflen = 20*1024;
- if(buflen > content_length)
- buflen = (int) content_length;
- char* buffer = new char[buflen + 1];
- __int64 sizesent = 0;
- while(sizesent < content_length)
- {
- int sizeread = m_content_stream->read(buflen, buffer);
- if(sizeread > 0)
- {
- sizesent += sizeread;
- try
- {
- m_socket.write(buffer, sizeread);
- }
- catch (IException *e)
- {
- StringBuffer estr;
- LOG(MCexception(e), "In CHttpMessage::send(%d) -- Exception(%d, %s) writing to socket(%d).", __LINE__, e->errorCode(), e->errorMessage(estr).str(), m_socket.OShandle());
- e->Release();
- retcode = -1;
- break;
- }
- catch(...)
- {
- ERRLOG("In CHttpMessage::send(%d) -- Unknown exception writing to socket(%d).", __LINE__, m_socket.OShandle());
- retcode = -1;
- break;
- }
- }
- else
- {
- ERRLOG("Error read from file");
- break;
- }
- }
- delete buffer;
- }
- return retcode;
- }
- int CHttpMessage::startSend()
- {
- StringBuffer sendbuf;
- constructHeaderBuffer(sendbuf, false);
-
- if (getEspLogLevel(queryContext())>LogNormal)
- DBGLOG("Start Sending chunked HTTP message:\n %s", sendbuf.str());
- try
- {
- m_socket.write(sendbuf.str(), sendbuf.length());
- }
- catch (IException *e)
- {
- StringBuffer estr;
- DBGLOG("In CHttpMessage::send() -- Exception(%d, %s) writing to socket(%d).", e->errorCode(), e->errorMessage(estr).str(), m_socket.OShandle());
- e->Release();
- return -1;
- }
- catch(...)
- {
- ERRLOG("In CHttpMessage::send() -- Unknown exception writing to socket(%d).", m_socket.OShandle());
- return -1;
- }
- return 0;
- }
- int CHttpMessage::sendChunk(const char *chunk)
- {
- if (getEspLogLevel(queryContext())>LogNormal)
- DBGLOG("Sending HTTP chunk:\n %s", chunk);
- try
- {
- m_socket.write(chunk, strlen(chunk));
- }
- catch (IException *e)
- {
- StringBuffer estr;
- DBGLOG("In CHttpMessage::send() -- Exception(%d, %s) writing to socket(%d).", e->errorCode(), e->errorMessage(estr).str(), m_socket.OShandle());
- e->Release();
- return -1;
- }
- catch(...)
- {
- ERRLOG("In CHttpMessage::send() -- Unknown exception writing to socket(%d).", m_socket.OShandle());
- return -1;
- }
- return 0;
- }
- int CHttpMessage::sendFinalChunk(const char *chunk)
- {
- if (getEspLogLevel(queryContext())>LogNormal)
- DBGLOG("Sending HTTP Final chunk:\n %s", chunk);
- try
- {
- m_socket.write(chunk, strlen(chunk));
- m_socket.close();
- }
- catch (IException *e)
- {
- StringBuffer estr;
- DBGLOG("In CHttpMessage::send() -- Exception(%d, %s) writing to socket(%d).", e->errorCode(), e->errorMessage(estr).str(), m_socket.OShandle());
- e->Release();
- return -1;
- }
- catch(...)
- {
- ERRLOG("In CHttpMessage::send() -- Unknown exception writing to socket(%d).", m_socket.OShandle());
- return -1;
- }
- return 0;
- }
- int CHttpMessage::close()
- {
- int ret = 0;
- try
- {
- if(&m_socket != NULL)
- {
- m_socket.shutdown();
- m_socket.close();
- }
- }
- catch (IException *e)
- {
- StringBuffer estr;
- ERRLOG("Exception(%d, %s) - CHttpMessage::close(), closing socket.", e->errorCode(), e->errorMessage(estr).str());
- e->Release();
- ret = -1;
- }
- catch(...)
- {
- ERRLOG("General Exception - CHttpMessage::close(), closing socket.");
- ret = -1;
- }
- return ret;
- }
- void CHttpMessage::setHeader(const char* headername, const char* headerval)
- {
- if(!headername || !*headername)
- return;
- StringBuffer val;
- val.append(headername).append(": ").append(headerval);
- ForEachItemIn(x, m_headers)
- {
- const char* curst = m_headers.item(x);
- if(!curst)
- continue;
- const char* colon = strchr(curst, ':');
- if(!colon)
- continue;
- if(!strnicmp(headername, curst, colon - curst))
- {
- m_headers.replace(val.str(), x);
- return;
- }
- }
- m_headers.append(val.str());
- }
- void CHttpMessage::addHeader(const char* headername, const char* headerval)
- {
- if(headername == NULL || strlen(headername) == 0)
- return;
- StringBuffer header;
- header.append(headername);
- header.append(": ");
- header.append(headerval);
- m_headers.append(header.str());
- }
- StringBuffer& CHttpMessage::getHeader(const char* headername, StringBuffer& headerval)
- {
- if(headername == NULL || strlen(headername) == 0)
- return headerval;
- ForEachItemIn(x, m_headers)
- {
- const char* header = m_headers.item(x);
- if(header == NULL)
- continue;
- const char* colon = strchr(header, ':');
- if(colon == NULL)
- continue;
- if(strncmp(headername, header, colon - header) == 0)
- {
- headerval.append(colon + 2);
- break;
- }
- }
- return headerval;
- }
- bool isSoapContentType(const char* contenttype)
- {
- if(contenttype == NULL)
- return false;
- else
- return Utils::strncasecmp(contenttype, HTTP_TYPE_TEXT_XML, strlen(HTTP_TYPE_TEXT_XML)) == 0 ||
- Utils::strncasecmp(contenttype, HTTP_TYPE_SOAP, strlen(HTTP_TYPE_SOAP)) == 0;
- }
- bool CHttpMessage::isSoapMessage()
- {
- if(m_content_type.get() == NULL)
- return false;
- else if(Utils::strncasecmp(m_content_type.get(), HTTP_TYPE_MULTIPART_RELATED, strlen(HTTP_TYPE_MULTIPART_RELATED)) == 0)
- {
- CMimeMultiPart* mpart = queryMultiPart();
- if(mpart == NULL)
- return false;
- CMimeBodyPart* bpart = mpart->queryRootPart();
- if(bpart != NULL && isSoapContentType(bpart->getContentType()))
- return true;
- else
- return false;
- }
- else
- return isSoapContentType(m_content_type.get());
- }
- bool CHttpMessage::isFormSubmission()
- {
- return ((hasContentType(NULL) && (m_paramCount + m_attachCount) > 0) ||
- hasContentType(HTTP_TYPE_MULTIPART_FORMDATA) ||
- hasContentType(HTTP_TYPE_FORM_ENCODED));
- }
- /******************************************************************************
- CHttpRequest Implementation
- *******************************************************************************/
- CHttpRequest::CHttpRequest(ISocket& socket) : CHttpMessage(socket), m_pathIsParsed(false), m_sstype(sub_serv_unknown), m_MaxRequestEntityLength(0)
- {
- };
- CHttpRequest::~CHttpRequest()
- {
- };
- StringBuffer& CHttpRequest::getMethod(StringBuffer & method)
- {
- return method.append(m_httpMethod.str());
- }
- void CHttpRequest::setMethod(const char* method)
- {
- m_httpMethod.clear().append(method);
- }
- StringBuffer& CHttpRequest::getPath(StringBuffer & path)
- {
- return path.append(m_httpPath.str());
- }
- void CHttpRequest::setPath(const char* path)
- {
- m_httpPath.clear().append(path);
- }
- void CHttpRequest::parseQueryString(const char* querystr)
- {
- if(!querystr || !*querystr)
- return;
- bool useHeap = false;
- int querystrlen = strlen(querystr);
- if(querystrlen >= 0x80000)
- useHeap = true;
- char* querystrbuf = NULL;
- if(useHeap)
- querystrbuf = (char*)malloc(querystrlen + 1);
- else
- querystrbuf = (char*)alloca(querystrlen + 1);
- strcpy(querystrbuf, querystr);
- char* ptr = querystrbuf;
- char* curname = ptr;
- char* curvalue = NULL;
- while(true)
- {
- while(*ptr != '\0' && *ptr != '=' && *ptr != '&')
- ptr++;
-
- if(*ptr == '\0')
- {
- StringBuffer nameval;
- Utils::url_decode(curname, nameval);
- addParameter(nameval.str(), "");
- break;
- }
- else if(*ptr == '=')
- {
- *ptr = '\0';
- ptr++;
- if(*ptr == '\0')
- {
- StringBuffer nameval;
- Utils::url_decode(curname, nameval);
- addParameter(nameval.str(), "");
- break;
- }
- else if(*ptr == '&')
- {
- StringBuffer nameval;
- Utils::url_decode(curname, nameval);
- addParameter(nameval.str(), "");
- ptr++;
- if(*ptr == '\0')
- break;
- else
- curname = ptr;
- }
- else
- {
- curvalue = ptr;
- while(*ptr != '\0' && *ptr != '&')
- ptr++;
- if(*ptr == '\0')
- {
- StringBuffer nameval;
- StringBuffer valueval;
- Utils::url_decode(curname, nameval);
- Utils::url_decode(curvalue, valueval);
- addParameter(nameval.str(), valueval.str());
- break;
- }
- else //*ptr == '&'
- {
- *ptr = '\0';
- ptr++;
- StringBuffer nameval;
- StringBuffer valueval;
- Utils::url_decode(curname, nameval);
- Utils::url_decode(curvalue, valueval);
- addParameter(nameval.str(), valueval.str());
- if(*ptr == '\0')
- break;
- else
- curname = ptr;
- }
- }
- }
- else if(*ptr == '&')
- {
- *ptr=0;
- StringBuffer nameval;
- Utils::url_decode(curname, nameval);
- addParameter(nameval.str(), "");
- ptr++;
- if(!*ptr)
- break;
- else
- curname = ptr;
- }
- }
- if(useHeap && querystrbuf != NULL)
- delete querystrbuf;
- }
- int CHttpRequest::parseFirstLine(char* oneline)
- {
- //if (getEspLogLevel()>LogNormal)
- // DBGLOG("First Line of request=%s", oneline);
- DBGLOG("HTTP First Line: %s", oneline);
- if(*oneline == 0)
- return -1;
- const char* curptr = oneline;
- StringBuffer method;
- curptr = Utils::getWord(curptr, method);
- if(!stricmp(method.str(), POST_METHOD))
- {
- setMethod(POST_METHOD);
- }
- else if(!stricmp(method.str(), GET_METHOD))
- {
- setMethod(GET_METHOD);
- }
- else if(!stricmp(method.str(), HEAD_METHOD))
- {
- setMethod(HEAD_METHOD);
- }
- StringBuffer pathbuf;
- curptr = Utils::getWord(curptr, pathbuf);
-
- int len = pathbuf.length();
- char* buff;
- if(len == 0)
- {
- buff = new char[2];
- buff[0] = '/';
- buff[1] = '\0';
- }
- else
- {
- if(pathbuf.charAt(0) != '/')
- {
- buff = new char[len + 2];
- buff[0] = '/';
- strcpy(buff + 1, pathbuf.str());
- }
- else
- {
- buff = new char[len + 1];
- strcpy(buff, pathbuf.str());
- }
- }
- char* qmark = strchr(buff, '?');
- if(qmark != NULL)
- {
- *qmark = '\0';
- }
- // Decode path
- StringBuffer path;
- Utils::url_decode(buff, path);
- setPath(path.str());
- // Parse and decode parameters
- if(qmark != NULL)
- {
- char* querystr = qmark + 1;
- m_paramstr.set(querystr);
- addParameter("__querystring", querystr); //MORE- requested by dimitri
- parseQueryString(querystr);
- }
- delete[] buff;
- return 0;
- }
- void CHttpRequest::parseCookieHeader(char* cookiestr)
- {
- if(cookiestr == NULL)
- return;
- int version;
- char* curword;
- char* curptr = cookiestr;
- const char* separators = ",;";
-
- curptr = Utils::getWord(curptr, curword, separators);
- StringBuffer name, value;
- Utils::parseNVPair(curword, name, value);
- CEspCookie* cookie = NULL;
- if(name.length() == 0 || stricmp(name.str(), "$Version"))
- {
- version = 0;
- cookie = new CEspCookie(name.str(), value.str());
- cookie->setVersion(version);
- m_cookies.append(*cookie);
- }
- else
- {
- version = atoi(value.str());
- }
- while(curptr != NULL && *curptr != 0)
- {
- curptr = Utils::getWord(curptr, curword, separators);
- if(curword == NULL)
- break;
- StringBuffer name, value;
- Utils::parseNVPair(curword, name, value);
- if(name.length() == 0)
- continue;
- if(name.charAt(0) != '$')
- {
- cookie = new CEspCookie(name.str(), value.str());
- cookie->setVersion(version);
- m_cookies.append(*cookie);
- }
- else if(stricmp(name.str(), "$Path") == 0 && cookie != NULL)
- cookie->setPath(value.str());
- else if(stricmp(name.str(), "$Domain") == 0 && cookie != NULL)
- cookie->setDomain(value.str());
- else if(stricmp(name.str(), "$Port") == 0 && cookie != NULL)
- cookie->setPorts(value.str());
- }
- }
- void CHttpRequest::parseEspPathInfo()
- {
- if (!m_pathIsParsed)
- {
- m_espPathEx.clear();
- m_espMethodName.clear();
- m_espServiceName.clear();
- size32_t pathlen=m_httpPath.length();
- if (!pathlen)
- m_sstype=(m_queryparams && m_queryparams->hasProp("main")) ? sub_serv_main : sub_serv_root;
- else
- {
- char *pathstr = strdup(m_httpPath.str());
- char *finger = pathstr;
-
- if (!strnicmp(finger, "http://", 7))
- finger+=7;
- char *thumb=finger;
- while (*thumb!=0 && *thumb!='/')
- {
- if (*thumb=='@' || *thumb==':')
- {
- finger=strchr(thumb, '/');
- break;
- }
- thumb++;
- }
- bool missingTrailSlash = false;
- if (finger)
- {
- while (*finger == '/')
- finger++;
- //look for the service and method names
- //
- if (finger && finger[0] != '\0')
- {
- thumb=strchr(finger, '/');
- if (thumb)
- {
- char *pathex = strchr(thumb+1, '/');
- if (pathex)
- {
- *pathex=0;
- m_espPathEx.append(pathex+1);
- }
-
- *thumb=0;
- m_espMethodName.append(thumb+1);
- }
- else
- missingTrailSlash = true;
- m_espServiceName.append(finger);
- }
- }
-
- free(pathstr);
- if (m_espMethodName.length())
- {
- if (!stricmp(m_espMethodName.str(), "files_"))
- m_sstype=sub_serv_files;
- else if (!stricmp(m_espMethodName.str(), "content_"))
- m_sstype=sub_serv_content;
- else if (!stricmp(m_espMethodName.str(), "result_"))
- m_sstype=sub_serv_result;
- else if (!stricmp(m_espMethodName.str(), "iframe"))
- m_sstype=sub_serv_iframe;
- else if (!stricmp(m_espMethodName.str(), "itext"))
- m_sstype=sub_serv_itext;
- else if (!stricmp(m_espMethodName.str(), "relogin_"))
- m_sstype=sub_serv_relogin;
- else if (!stricmp(m_espMethodName.str(), "version_"))
- m_sstype=sub_serv_getversion;
- }
- //not a special service URL, determine the action type
- if (m_sstype==sub_serv_unknown)
- {
- if (m_queryparams && (m_queryparams->hasProp("wsdl") || m_queryparams->hasProp("wsdl_ext")))
- m_sstype=sub_serv_wsdl;
- else if (m_queryparams && (m_queryparams->hasProp("xsd")))
- m_sstype=sub_serv_xsd;
- else if (m_queryparams && (m_queryparams->hasProp("reqxml_")))
- m_sstype=sub_serv_reqsamplexml;
- else if (m_queryparams && (m_queryparams->hasProp("respxml_")))
- m_sstype=sub_serv_respsamplexml;
- else if (m_queryparams && (m_queryparams->hasProp("soap_builder_")))
- m_sstype=sub_serv_soap_builder;
- else if (m_queryparams && m_queryparams->hasProp("config_"))
- m_sstype=sub_serv_config;
- else if (m_espServiceName.length()==0)
- m_sstype=(m_queryparams && m_queryparams->hasProp("main")) ? sub_serv_main : sub_serv_root;
- else if (m_espMethodName.length()==0)
- m_sstype = missingTrailSlash ? sub_serv_index_redirect : sub_serv_index;
- else if (m_queryparams && m_queryparams->hasProp("form_"))
- m_sstype=sub_serv_form;
- else if (m_queryparams && m_queryparams->hasProp("form"))
- m_sstype=sub_serv_xform;
- else if (isUpload())
- m_sstype=sub_serv_file_upload;
- else if (getParameterCount())// queryParamStr()!=NULL && *queryParamStr()!=0)
- m_sstype=sub_serv_query;
- else
- m_sstype=sub_serv_method;
- }
- }
- m_pathIsParsed=true;
- }
- }
- void CHttpRequest::getEspPathInfo(sub_service &sstype, StringBuffer *pathEx, StringBuffer *service, StringBuffer *method, bool upcase)
- {
- parseEspPathInfo();
- sstype = m_sstype;
- if (pathEx)
- {
- pathEx->clear().append(m_espPathEx);
- if (upcase)
- pathEx->toUpperCase();
- }
- if (service)
- {
- service->clear().append(m_espServiceName);
- service->toUpperCase();
- }
- if (method)
- {
- method->clear().append(m_espMethodName);
- method->toUpperCase();
- }
- }
-
- void CHttpRequest::getBasicRealm(StringBuffer& realm)
- {
- StringBuffer authheader;
- getHeader("WWW-Authenticate", authheader);
- if(authheader.length() == 0)
- return;
-
- if(Utils::strncasecmp(authheader.str(), "Basic ", strlen("Basic ")) != 0)
- return;
- const char* strt = strchr(authheader.str(), '\"');
- ++strt;
- if (strt)
- {
- const char* end = strchr(strt, '\"');
- if (end)
- {
- realm.append(strt, 0, end - strt);
- }
- }
- }
- int CHttpRequest::getPeerPort()
- {
- char peername[256];
- return m_socket.peer_name(peername, 256);
- }
- StringBuffer& CHttpRequest::getPeer(StringBuffer& Peer)
- {
- StringBuffer ForwardIPs;
- getHeader("X-Forwarded-For", ForwardIPs);
-
- if(ForwardIPs.length() != 0)
- {
- //IPs will ne in the form xxx.xxx.xxx.xxx,yyy.yyy.yyy.yyy,zzz.zzz.zzz.zzz
- //We want to take the first IP in the list
- const char* strt = strchr(ForwardIPs.str(), ',');
- if(strt!= NULL)
- Peer.append(strt - ForwardIPs.str(),ForwardIPs.str());
- else
- Peer.appendf("%s",ForwardIPs.str());
- }
- else
- {
- char peerchr[256];
- int port = m_socket.peer_name(peerchr, 256);
- Peer.append(peerchr);
- }
- return Peer;
- }
- void CHttpRequest::getBasicAuthorization(StringBuffer& userid, StringBuffer& password,StringBuffer& realm)
- {
- StringBuffer authheader;
- getHeader("Authorization", authheader);
- if(authheader.length() == 0)
- return;
- if(Utils::strncasecmp(authheader.str(), "Basic ", strlen("Basic ")) != 0)
- return;
- StringBuffer uidpair;
- Utils::base64decode(authheader.length() - strlen("Basic "), authheader.str() + strlen("Basic "), uidpair);
-
- const char* pairstr = strchr(uidpair.str(), '\\');
- if(pairstr!=NULL)
- {
- realm.append(pairstr - uidpair.str(),uidpair.str());
- pairstr++;
- }
- else
- {
- pairstr = uidpair.str();
- getBasicRealm(realm);
- }
-
- const char* colon = strchr(pairstr, ':');
- if(colon == NULL)
- {
- userid.append(pairstr);
- }
- else
- {
- userid.append(colon - pairstr, pairstr);
- password.append(colon + 1);
- }
- }
- int CHttpRequest::receive(IMultiException *me)
- {
- if (CHttpMessage::receive(false, me)==-1)
- return -1;
-
- //if(hasContentType("application/x-www-form-urlencoded"))
- if(hasContentType(HTTP_TYPE_FORM_ENCODED))
- {
- parseQueryString(m_content.str());
- }
- else if(hasContentType(HTTP_TYPE_MULTIPART_FORMDATA) && !isUpload())
- {
- CMimeMultiPart* mpart = queryMultiPart();
- if(mpart != NULL)
- {
- int count = mpart->getBodyCount();
- for(int i = 0; i < count; i++)
- {
- CMimeBodyPart* bpart = mpart->queryBodyPart(i);
- if(bpart == NULL)
- continue;
- const char* cdisp = bpart->getContentDisposition();
- StringBuffer contentbuf;
- bpart->getContent(contentbuf);
- StringBuffer namebuf;
- char* curword = NULL;
- char* curptr = (char*)cdisp;
- const char* separators = ";";
-
- bool isFile = false;
- StringBuffer filename;
- while(curptr != NULL && *curptr != 0)
- {
- curptr = Utils::getWord(curptr, curword, separators, true);
- if(curword == NULL)
- break;
- StringBuffer name, value;
- Utils::parseNVPair(curword, name, value);
- if(name.length() > 0 && stricmp(name.str(), "name") == 0)
- {
- namebuf.append(value.str());
- }
- else if(name.length() > 0 && stricmp(name.str(), "filename") == 0)
- {
- value.swapWith(filename);
- isFile = true;
- }
- }
- if(!isFile)
- addParameter(namebuf.str(), contentbuf.str());
- else
- {
- addParameter(namebuf.str(), filename.str());
- addAttachment(namebuf.str(), contentbuf);
- }
- }
- }
- }
- m_context->addTraceSummaryTimeStamp("rcv");
- return 0;
- }
- void CHttpRequest::updateContext()
- {
- if(m_context)
- {
- m_context->setContextPath(m_httpPath.str());
- StringBuffer temp;
- getPeer(temp);
- if(temp.length())
- m_context->setPeer(temp.str());
-
- m_context->setRequestParameters(queryParameters());
- short servPort;
- temp.clear();
- getServAddress(temp, servPort);
- m_context->setServAddress(temp.str(), servPort);
- StringBuffer userid, password, realm;
- getBasicAuthorization(userid, password, realm);
- if(userid.length() > 0)
- {
- m_context->setUserID(userid.str());
- m_context->setPassword(password.str());
- m_context->setRealm(realm.str());
- }
- if (m_queryparams)
- {
- if (m_queryparams->getPropInt("no_ns_"))
- m_context->addOptions(ESPCTX_NO_NAMESPACES);
- if (m_queryparams->hasProp("wsdl"))
- m_context->addOptions(ESPCTX_WSDL);
- if (m_queryparams->hasProp("wsdl_ext"))
- m_context->addOptions(ESPCTX_WSDL|ESPCTX_WSDL_EXT);
- if (m_queryparams->hasProp("no_annot_"))
- m_context->addOptions(ESPCTX_NO_ANNOTATION);
- if (m_queryparams->hasProp("all_annot_"))
- m_context->addOptions(ESPCTX_ALL_ANNOTATION);
- }
- // set client version
- StringBuffer action;
- getHeader("SOAPAction", action);
- // URL first, then SOAPAction
- const char *verstr = queryParameters()->queryProp("ver_");
- if (verstr && *verstr)
- m_context->setClientVersion(atof(verstr));
- else
- {
- verstr=strstr(action.str(), "ver_=");
- if (verstr)
- m_context->setClientVersion(atof(verstr+5));
- else
- m_context->setClientVersion(0.0);
- }
- StringBuffer useragent;
- getHeader("User-Agent", useragent);
- m_context->setUseragent(useragent.str());
- }
- }
- StringBuffer& CHttpRequest::constructHeaderBuffer(StringBuffer& headerbuf, bool inclLength)
- {
- if(m_httpMethod.length() > 0)
- headerbuf.append(queryMethod()).append(" ");
- else
- headerbuf.append("POST ");
- if(m_httpPath.length() > 0)
- headerbuf.append(queryPath()).append(" ");
- else
- headerbuf.append("/ ");
- if(m_version.length() > 0)
- headerbuf.append(m_version.get());
- else
- headerbuf.append(HTTP_VERSION);
- headerbuf.append("\r\n");
- if(m_host.length() > 0)
- {
- headerbuf.append("Host: ").append(m_host.get());
- if(m_port != 80)
- {
- headerbuf.append(":").append(m_port);
- }
- headerbuf.append("\r\n");
- }
- headerbuf.append("Content-Type: ");
- if(m_content_type.length() > 0)
- headerbuf.append(m_content_type.get());
- else
- headerbuf.append("text/xml; charset=UTF-8");
- headerbuf.append("\r\n");
- if(inclLength && m_content_length > 0)
- headerbuf.append("Content-Length: ").append(m_content_length).append("\r\n");
- if(m_cookies.length() > 0)
- {
- headerbuf.append("Cookie: ");
- int version = m_cookies.item(0).getVersion();
- if(version >= 1)
- headerbuf.append("$Version=").append('"').append(version).append('"').append(',');
- ForEachItemIn(x, m_cookies)
- {
- CEspCookie* cookie = &m_cookies.item(x);
- if(cookie == NULL)
- continue;
- cookie->appendToRequestHeader(headerbuf);
- }
- headerbuf.append("\r\n");
- }
-
- ForEachItemIn(x, m_headers)
- {
- const char* oneheader = (const char*)m_headers.item(x);
- headerbuf.append(oneheader).append("\r\n");
- }
- headerbuf.append("\r\n");
- return headerbuf;
- }
- int CHttpRequest::processHeaders(IMultiException *me)
- {
- char oneline[MAX_HTTP_HEADER_LEN + 2];
- int lenread = m_bufferedsocket->readline(oneline, MAX_HTTP_HEADER_LEN + 1, me);
- if(lenread <= 0) //special case client connected and disconnected, load balancer ping?
- return -1;
- else if (lenread > MAX_HTTP_HEADER_LEN)
- throw createEspHttpException(HTTP_STATUS_BAD_REQUEST_CODE, "Bad Request", HTTP_STATUS_BAD_REQUEST);
- m_header.set(oneline);
- parseFirstLine(oneline);
-
- lenread = m_bufferedsocket->readline(oneline, MAX_HTTP_HEADER_LEN + 1, me);
- while(lenread >= 0 && oneline[0] != '\0')
- {
- if(lenread > MAX_HTTP_HEADER_LEN)
- throw createEspHttpException(HTTP_STATUS_BAD_REQUEST_CODE, "Bad Request", HTTP_STATUS_BAD_REQUEST);
- m_header.append('\n').append(oneline);
- parseOneHeader(oneline);
- lenread = m_bufferedsocket->readline(oneline, MAX_HTTP_HEADER_LEN + 1, me);
- }
- if (getEspLogRequests() || getEspLogLevel()>LogNormal)
- {
- DBGLOG("Request Headers:\n%s", m_header.str());
- }
- if(m_content_length > 0 && m_MaxRequestEntityLength > 0 && m_content_length > m_MaxRequestEntityLength && (!isUpload()))
- throw createEspHttpException(HTTP_STATUS_BAD_REQUEST_CODE, "The request length was too long.", HTTP_STATUS_BAD_REQUEST);
- return 0;
- }
- int CHttpRequest::readContentToFile(StringBuffer netAddress, StringBuffer path)
- {
- char buf[1024 + 1];
- int buflen = 1024;
- int readlen = 0;
- __int64 totallen = m_content_length64;
- if(buflen > totallen)
- buflen = (int) totallen;
- StringBuffer lengthStr;
- lengthStr.append(m_content_length64);
- Owned<CMimeMultiPart> m_multipart = new CMimeMultiPart("1.0", m_content_type.get(), "", "", "");
- m_multipart->parseContentType(m_content_type.get());
- //Read the first one of data to find out the file name, as well as the beginning of the file content
- bool lastChuck = false;
- MemoryBuffer fileContent;
- StringBuffer fileName;
- while(fileName.length() < 1)
- {
- readlen = m_bufferedsocket->read(buf, buflen);
- if(readlen < 0)
- {
- DBGLOG(">> Socket timed out because of incorrect Content-Length passed in from the other side");
- break;
- }
- if(readlen == 0)
- break;
-
- buf[readlen] = 0;
- fileContent.append(readlen, buf);
- //find out the file name, as well as the beginning of the file content
- m_multipart->readUploadFile(fileContent, fileName);
- totallen -= readlen;
- if(totallen <= 0)
- break;
- if(buflen > totallen)
- buflen = (int) totallen;
- }
- if (fileName.length() < 1)
- {
- DBGLOG(">> File cannot be uploaded.");
- return 0;
- }
- //Create IFile to store the file
- StringBuffer name0(fileName), name1(fileName), fileToSave, fileToUse;
- char* str = (char*) name1.reverse().str();
- char* pStr = (char*) strchr(str, '\\');
- if (!pStr)
- pStr = strchr(str, '/');
- if (pStr)
- {
- pStr[0] = 0;
- name0.clear().append(str).reverse();
- }
- fileToSave.appendf("%s/%s.part", path.str(), name0.str());
- fileToUse.appendf("%s/%s", path.str(), name0.str());
- RemoteFilename rfn;
- SocketEndpoint ep;
- ep.set(netAddress.str());
- rfn.setPath(ep, fileToSave.str());
- Owned<IFile> file = createIFile(rfn);
- if (!file)
- {
- DBGLOG(">> File %s cannot be uploaded.", name0.str());
- return 0;
- }
- Owned<IFileIO> fileio = file->open(IFOcreate);
- if (!fileio)
- {
- DBGLOG(">> File %s cannot be uploaded.", name0.str());
- return 0;
- }
- //If this is the last chuck of data, we need to remove the boundry line at the end of data
- if(totallen <= 0)
- lastChuck = true;
- else if(totallen < 1024)
- { //if there is only one chuck left, the boundry line may be broken in the first chuck and the last chuck.
- lastChuck = true;
- readlen = m_bufferedsocket->read(buf, buflen);
- if(readlen < 0)
- {
- DBGLOG(">> Socket timed out because of incorrect Content-Length passed in from the other side");
- return 0;
- }
- if(readlen == 0)
- return 0;
- buf[readlen] = 0;
- fileContent.append(readlen, buf);
- }
- //remove the boundry line at the end of data
- if (lastChuck)
- m_multipart->checkEndOfFile(fileContent);
- //Save the data into the file
- if (fileio->write(0, fileContent.length(), fileContent.toByteArray()) != fileContent.length())
- {
- DBGLOG(">> File %s cannot be uploaded.", name0.str());
- return 0;
- }
- if(lastChuck)
- {
- file->rename(fileToUse.str());
- return 0;
- }
- //The file has more than two chucks. Now, look though the rest of the chucks.
- __int64 offset = fileContent.length();
- for(;;)
- {
- readlen = m_bufferedsocket->read(buf, buflen);
- if(readlen < 0)
- {
- DBGLOG(">> Socket timed out because of incorrect Content-Length passed in from the other side");
- break;
- }
- if(readlen == 0)
- break;
-
- buf[readlen] = 0;
- fileContent.clear().append(readlen, buf);
-
- //For the last one or two chucks, remove the boundry line at the end of data.
- totallen -= readlen;
- if(totallen <= 0)
- lastChuck = true;
- else if(totallen < 1024)
- {
- lastChuck = true;
- buflen = (int) totallen;
- readlen = m_bufferedsocket->read(buf, buflen);
- if(readlen < 0)
- {
- DBGLOG(">> Socket timed out because of incorrect Content-Length passed in from the other side");
- break;
- }
- if(readlen == 0)
- break;
- buf[readlen] = 0;
- fileContent.append(readlen, buf);
- }
- if (lastChuck)
- {
- m_multipart->checkEndOfFile(fileContent);
- DBGLOG(">> The length of the last chuck=<%d>", fileContent.length());
- }
- if (fileio->write(offset, fileContent.length(), fileContent.toByteArray()) != fileContent.length())
- {
- DBGLOG(">> File %s cannot be uploaded.", name0.str());
- break;
- }
- if (lastChuck)
- break;
- offset += readlen;
- }
- file->rename(fileToUse.str());
- return 0;
- }
- /******************************************************************************
- CHttpResponse Implementation
- *******************************************************************************/
- CHttpResponse::CHttpResponse(ISocket& socket) : CHttpMessage(socket), m_timeout(BSOCKET_CLIENT_READ_TIMEOUT)
- {
- }
- CHttpResponse::~CHttpResponse()
- {
- }
- void CHttpResponse::setTimeOut(unsigned int timeout)
- {
- m_timeout = timeout;
- }
- void CHttpResponse::setStatus(const char* status)
- {
- m_status.set(status);
- }
- StringBuffer& CHttpResponse::getStatus(StringBuffer& status)
- {
- status.append(m_status.get());
- return status;
- }
- StringBuffer& CHttpResponse::constructHeaderBuffer(StringBuffer& headerbuf, bool inclLen)
- {
- if(m_version.length() > 0)
- headerbuf.append(m_version.get()).append(" ");
- else
- headerbuf.append(HTTP_VERSION).append(" ");
- if(m_status.length() > 0)
- headerbuf.append(m_status.get());
- else
- headerbuf.append(HTTP_STATUS_OK);
- headerbuf.append("\r\n");
-
- headerbuf.append("Content-Type: ");
- if(m_content_type.length() > 0)
- headerbuf.append(m_content_type.get());
- else
- headerbuf.append("text/xml; charset=UTF-8");
- headerbuf.append("\r\n");
- if(inclLen && m_content_length > 0)
- headerbuf.append("Content-Length: ").append(m_content_length).append("\r\n");
- headerbuf.append("Connection: close\r\n");
-
- ForEachItemIn(x, m_cookies)
- {
- CEspCookie* cookie = &m_cookies.item(x);
- if(cookie == NULL)
- continue;
- StringBuffer cookiehn;
- cookie->getSetCookieHeaderName(cookiehn);
- headerbuf.append(cookiehn.str()).append(": ");
- cookie->appendToResponseHeader(headerbuf);
- headerbuf.append("\r\n");
- }
- ForEachItemIn(i, m_headers)
- {
- const char* oneheader = (const char*)m_headers.item(i);
- headerbuf.append(oneheader).append("\r\n");
- }
-
- if(m_context.get())
- {
- StringArray& customHeaders = m_context->queryCustomHeaders();
- ForEachItemIn(j, customHeaders)
- {
- const char* oneheader = (const char*)customHeaders.item(j);
- if(oneheader && *oneheader)
- headerbuf.append(oneheader).append("\r\n");
- }
- }
- headerbuf.append("\r\n");
- return headerbuf;
- }
- int CHttpResponse::parseFirstLine(char* oneline)
- {
- if(*oneline == 0)
- return -1;
- if (getEspLogLevel()>LogNormal)
- DBGLOG("http response status = %s", oneline);
- char* ptr = oneline;
- while(*ptr != '\0' && *ptr != ' ')
- ptr++;
- if(*ptr != '\0')
- {
- *ptr = 0;
- ptr++;
- }
- m_version.set(oneline);
- while(*ptr == ' ')
- ptr++;
- m_status.set(ptr);
- return 0;
- }
- void CHttpResponse::parseOneCookie(char* cookiestr)
- {
- if(cookiestr == NULL)
- return;
- char* curword;
- char* curptr = cookiestr;
- CEspCookie* cookie = NULL;
- curptr = Utils::getWord(curptr, curword, ";");
- StringBuffer name, value;
- Utils::parseNVPair(curword, name, value);
- if(name.length() == 0)
- return;
- cookie = new CEspCookie(name.str(), value.str());
- m_cookies.append(*cookie);
- while(curptr != NULL && *curptr != 0)
- {
- curptr = Utils::getWord(curptr, curword, ";");
- if(curword == NULL)
- break;
- StringBuffer name, value;
- Utils::parseNVPair(curword, name, value);
- if(name.length() == 0)
- continue;
- else if(stricmp(name.str(), "Version") == 0)
- cookie->setVersion(atoi(value.str()));
- else if(stricmp(name.str(), "Path") == 0)
- cookie->setPath(value.str());
- else if(stricmp(name.str(), "Domain") == 0)
- cookie->setDomain(value.str());
- else if(stricmp(name.str(), "Port") == 0)
- cookie->setPorts(value.str());
- else if(stricmp(name.str(), "Max-Age") == 0)
- cookie->setMaxAge(atoi(value.str()));
- else if(stricmp(name.str(), "Discard") == 0)
- cookie->setDiscard(true);
- else if(stricmp(name.str(), "Secure") == 0)
- cookie->setSecure(true);
- else if(stricmp(name.str(), "Comment") == 0)
- cookie->setComment(value.str());
- else if(stricmp(name.str(), "CommentURL") == 0)
- cookie->setCommentURL(value.str());
-
- }
- }
- void CHttpResponse::parseCookieHeader(char* cookiestr)
- {
- if(cookiestr == NULL)
- return;
- //TODO: for now assume each Set-Cookie only has one cookie.
- parseOneCookie(cookiestr);
- }
- void CHttpResponse::sendBasicChallenge(const char* realm, bool includeContent)
- {
- StringBuffer authheader;
- authheader.appendf("Basic realm=\"%s\"", realm);
- addHeader("WWW-Authenticate", authheader.str());
- if (includeContent)
- {
- setContentType("text/html; charset=UTF-8");
- setContent(
- "<html xmlns=\"http://www.w3.org/1999/xhtml\">"
- "<head>"
- "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>"
- "<title>ESP - Access Denied</title>"
- "<script type='text/javascript'>"
- "function closeWin() { top.opener=top; top.close(); }"
- "</script>"
- "</head>"
- "<body onload=\"javascript:closeWin();\">"
- "<b>Access Denied -- Valid username and password required!</b>"
- "</body>"
- "</html>"
- );
- }
- setStatus(HTTP_STATUS_UNAUTHORIZED);
- send();
- }
- void CHttpResponse::sendBasicChallenge(const char* realm, const char* content)
- {
- StringBuffer authheader;
- authheader.appendf("Basic realm=\"%s\"", realm);
- addHeader("WWW-Authenticate", authheader.str());
- if (content != NULL && *content != '\0')
- {
- setContentType("text/html; charset=UTF-8");
- setContent(content);
- }
- setStatus(HTTP_STATUS_UNAUTHORIZED);
- send();
- }
- int CHttpResponse::processHeaders(IMultiException *me)
- {
- char oneline[MAX_HTTP_HEADER_LEN + 1];
- int lenread = m_bufferedsocket->readline(oneline, MAX_HTTP_HEADER_LEN, me);
- if(lenread <= 0)
- return -1;
-
- // Process "100 Continue" headers
- // Some HTTP/1.1 webservers may send back "100 Continue" before it reads the posted request body.
- while(Utils::strncasecmp(oneline, "HTTP/1.1 100", strlen("HTTP/1.1 100")) == 0)
- {
- //Read until empty line, meaning the end of "100 Continue" part
- while(lenread >= 0 && oneline[0] != '\0')
- {
- lenread = m_bufferedsocket->readline(oneline, MAX_HTTP_HEADER_LEN, me);
- }
-
- // Read the next line, should be the status line.
- lenread = m_bufferedsocket->readline(oneline, MAX_HTTP_HEADER_LEN, me);
- if(lenread <= 0)
- return 0;
- }
- parseFirstLine(oneline);
- lenread = m_bufferedsocket->readline(oneline, MAX_HTTP_HEADER_LEN, me);
- while(lenread >= 0 && oneline[0] != '\0')
- {
- parseOneHeader(oneline);
- lenread = m_bufferedsocket->readline(oneline, MAX_HTTP_HEADER_LEN, me);
- }
- return 0;
- }
- bool CHttpResponse::httpContentFromFile(const char *filepath)
- {
- StringBuffer mimetype;
- MemoryBuffer content;
- bool ok = ::httpContentFromFile(filepath, mimetype, content);
- if (ok)
- {
- setContent(content.length(), content.toByteArray());
- setContentType(mimetype.str());
- setStatus(HTTP_STATUS_OK);
- }
- else
- {
- setStatus(HTTP_STATUS_NOT_FOUND);
- }
- return ok;
- }
- int CHttpResponse::receive(IMultiException *me)
- {
- // If it's receiving a response, it's behaving as the client side of this conversation.
- if(m_bufferedsocket.get() != NULL)
- m_bufferedsocket->setReadTimeout(m_timeout);
-
- return CHttpMessage::receive(me);
- }
- int CHttpResponse::receive(bool alwaysReadContent, IMultiException *me)
- {
- // If it's receiving a response, it's behaving as the client side of this conversation.
- if(m_bufferedsocket.get() != NULL)
- m_bufferedsocket->setReadTimeout(m_timeout);
-
- if (processHeaders(me)==-1)
- return -1;
- if (getEspLogLevel()>LogNormal)
- DBGLOG("Response headers processed! content_length = %d", m_content_length);
-
- char status_class = '2';
- if(m_status.length() > 0)
- status_class = *(m_status.get());
- if(m_content_length > 0)
- {
- readContent();
- if (getEspLogLevel()>LogNormal)
- DBGLOG("length of response content read = %d", m_content.length());
- }
- else if(alwaysReadContent && status_class != '4' && status_class != '5' && m_content_length == -1)
- {
- //HTTP protocol does not require a content length: read until socket closed
- readContentTillSocketClosed();
- if (getEspLogLevel()>LogNormal)
- DBGLOG("length of content read = %d", m_content.length());
- }
-
- if (getEspLogRequests() || getEspLogLevel()>LogNormal)
- {
- if(isTextMessage())
- DBGLOG("received HTTP response = %s", m_content.str());
- }
- return 0;
- }
- int CHttpResponse::sendException(IEspHttpException* e)
- {
- StringBuffer msg;
- e->errorMessage(msg);
- setStatus(e->getHttpStatus());
- setContentType(HTTP_TYPE_TEXT_PLAIN);
- setContent(msg.str());
- send();
- return 0;
- }
- bool CHttpResponse::handleExceptions(IXslProcessor *xslp, IMultiException *me, const char *serv, const char *meth, const char *errorXslt)
- {
- IEspContext *context=queryContext();
- if (me->ordinality()>0)
- {
- StringBuffer text;
- me->errorMessage(text);
- text.append('\n');
- WARNLOG("Exception(s) in %s::%s - %s", serv, meth, text.str());
- if (errorXslt)
- {
- me->serialize(text.clear());
- StringBuffer theOutput;
- xslTransformHelper(xslp, text.str(), errorXslt, theOutput, context->queryXslParameters());
- setContent(theOutput.str());
- setContentType("text/html");
- send();
- return true;
- }
- }
- return false;
- }
|