Beispiel #1
0
bool CHTTPSock::PrintErrorPage(unsigned int uStatusId,
                               const CString& sStatusMsg,
                               const CString& sMessage) {
    if (SentHeader()) {
        DEBUG("PrintErrorPage(): Header was already sent");
        return false;
    }

    CString sPage =
        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
        "<!DOCTYPE html>\r\n"
        "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" "
        "xml:lang=\"en\">\r\n"
        "<head>\r\n"
        "<meta charset=\"UTF-8\"/>\r\n"
        "<title>" +
        CString(uStatusId) + " " + sStatusMsg.Escape_n(CString::EHTML) +
        "</title>\r\n"
        "</head>\r\n"
        "<body>\r\n"
        "<h1>" +
        sStatusMsg.Escape_n(CString::EHTML) +
        "</h1>\r\n"
        "<p>" +
        sMessage.Escape_n(CString::EHTML) +
        "</p>\r\n"
        "<hr/>\r\n"
        "<p>" +
        CZNC::GetTag(false, /* bHTML = */ true) +
        "</p>\r\n"
        "</body>\r\n"
        "</html>\r\n";

    PrintHeader(sPage.length(), "text/html; charset=utf-8", uStatusId,
                sStatusMsg);
    Write(sPage);
    Close(Csock::CLT_AFTERWRITE);

    return true;
}
Beispiel #2
0
bool CHTTPSock::Redirect(const CString& sURL) {
	if (SentHeader()) {
		DEBUG("Redirect() - Header was already sent");
		return false;
	} else if(!sURL.StartsWith("/")) {
		// HTTP/1.1 only admits absolute URIs for the Location header.
		DEBUG("Redirect to relative URI [" + sURL + "] is not allowed.");
		return false;
	} else {
		CString location = m_sURIPrefix + sURL;

		DEBUG("- Redirect to [" << location << "] with prefix [" + m_sURIPrefix + "]");
		AddHeader("Location", location);
		PrintErrorPage(302, "Found", "The document has moved <a href=\"" + location.Escape_n(CString::EHTML) + "\">here</a>.");

		return true;
	}
}
Beispiel #3
0
	bool ConvertCharset(const VCString& vsFrom, const CString& sTo, CString& sData)
	{
		CString sDataCopy(sData);

		if(!m_bForce)
		{
			// check whether sData already is encoded with the right charset:
			iconv_t icTest = iconv_open(sTo.c_str(), sTo.c_str());
			if(icTest != (iconv_t)-1)
			{
				size_t uTest = GetConversionLength(icTest, sData);
				iconv_close(icTest);

				if(uTest != (size_t)-1 && uTest != (size_t)-2)
				{
					DEBUG("charset: [" + sData.Escape_n(CString::EURL) + "] is valid [" + sTo + "] already.");
					return true;
				}
			}
		}

		bool bConverted = false;

		// try all possible source charsets:
		for(VCString::const_iterator itf = vsFrom.begin(); itf != vsFrom.end(); ++itf)
		{
			if(ConvertCharset(*itf, sTo, sDataCopy))
			{
				// conversion successful!
				sData = sDataCopy;
				bConverted = true;
				break;
			}
			else
			{
				// reset string and try the next charset:
				sDataCopy = sData;
			}
		}

		return bConverted;
	}
Beispiel #4
0
static int testString(const CString& in, const CString& url,
		const CString& html, const CString& sql) {
	CString out;
	int errors = 0;

	// Encode, then decode again and check we still got the same string

	out = in.Escape_n(CString::EASCII, CString::EURL);
	errors += testEqual(out, url, "EURL encode");
	out = out.Escape_n(CString::EURL, CString::EASCII);
	errors += testEqual(out, in, "EURL decode");

	out = in.Escape_n(CString::EASCII, CString::EHTML);
	errors += testEqual(out, html, "EHTML encode");
	out = out.Escape_n(CString::EHTML, CString::EASCII);
	errors += testEqual(out, in, "EHTML decode");

	out = in.Escape_n(CString::EASCII, CString::ESQL);
	errors += testEqual(out, sql, "ESQL encode");
	out = out.Escape_n(CString::ESQL, CString::EASCII);
	errors += testEqual(out, in, "ESQL decode");

	return errors;
}
Beispiel #5
0
/**
 * Shorthand for encoding a string for a URL.
 *
 * @param str String to be encoded
 * @return Encoded string
 */
CString urlencode(const CString& str)
{
	return str.Escape_n(CString::EASCII, CString::EURL);
}
Beispiel #6
0
	bool ConvertCharset(const CString& sFrom, const CString& sTo, CString& sData)
	{
		if(sData.empty()) return true;

		DEBUG("charset: Trying to convert [" + sData.Escape_n(CString::EURL) + "] from [" + sFrom + "] to [" + sTo + "]...");

		iconv_t ic = iconv_open(sTo.c_str(), sFrom.c_str());
		if(ic == (iconv_t)-1) return false;

		size_t uLength = GetConversionLength(ic, sData);

		if(uLength == (size_t)-1)
		{
			// incompatible input encoding.
			iconv_close(ic);
			return false;
		}
		else if(uLength == (size_t)-2)
		{
			// internal error, preserve errno from GetConversionLength:
			int tmp_errno = errno;
			iconv_close(ic);
			errno = tmp_errno;
			return false;
		}
		else
		{
			// no error, so let's do the actual conversion.

			iconv(ic, NULL, NULL, NULL, NULL); // reset

			// state vars for iconv:
			size_t uResultBufSize = uLength + 1;
			char *pResult = new char[uResultBufSize];
			memset(pResult, 0, uResultBufSize);
			char *pResultWalker = pResult;
			const char* pIn = sData.c_str();
			size_t uInLen = sData.size();

			// let's fcking do it!
			size_t uResult = iconv(ic, (ICONV_CONST char**)&pIn, &uInLen, &pResultWalker, &uResultBufSize);
			bool bResult = (uResult != (size_t)-1);

			iconv_close(ic);

			if(bResult)
			{
				sData.assign(pResult, uLength);

				DEBUG("charset: Converted: [" + sData.Escape_n(CString::EURL) + "] from [" + sFrom + "] to [" + sTo + "]!");
			}
			else
			{
				DEBUG("Conversion failed: [" << uResult << "]");
			}

			delete[] pResult;

			return bResult;
		}
	}
Beispiel #7
0
// GTest uses this function to output objects
void PrintTo(const CString& s, std::ostream* o) {
	*o << '"' << s.Escape_n(CString::EASCII, CString::EDEBUG) << '"';
}
Beispiel #8
0
bool CTemplate::Print(const CString& sFileName, ostream& oOut) {
	if (sFileName.empty()) {
		DEBUG("Empty filename in CTemplate::Print()");
		return false;
	}

	CFile File(sFileName);

	if (!File.Open()) {
		DEBUG("Unable to open file [" + sFileName + "] in CTemplate::Print()");
		return false;
	}

	CString sLine;
	CString sSetBlockVar;
	bool bValidLastIf = false;
	bool bInSetBlock = false;
	unsigned long uFilePos = 0;
	unsigned long uCurPos = 0;
	unsigned int uLineNum = 0;
	unsigned int uNestedIfs = 0;
	unsigned int uSkip = 0;
	bool bLoopCont = false;
	bool bLoopBreak = false;
	bool bExit = false;

	while (File.ReadLine(sLine)) {
		CString sOutput;
		bool bFoundATag = false;
		bool bTmplLoopHasData = false;
		uLineNum++;
		CString::size_type iPos = 0;
		uCurPos = uFilePos;
		unsigned int uLineSize = sLine.size();
		bool bBroke = false;

		while (1) {
			iPos = sLine.find("<?");

			if (iPos == CString::npos) {
				break;
			}

			uCurPos += iPos;
			bFoundATag = true;

			if (!uSkip) {
				sOutput += sLine.substr(0, iPos);
			}

			sLine = sLine.substr(iPos +2);

			CString::size_type iPos2 = sLine.find("?>");

			// Make sure our tmpl tag is ended properly
			if (iPos2 == CString::npos) {
				DEBUG("Template tag not ended properly in file [" + sFileName + "] [<?" + sLine + "]");
				return false;
			}

			uCurPos += iPos2 +4;

			CString sMid = CString(sLine.substr(0, iPos2)).Trim_n();

			// Make sure we don't have a nested tag
			if (sMid.find("<?") == CString::npos) {
				sLine = sLine.substr(iPos2 +2);
				CString sAction = sMid.Token(0);
				CString sArgs = sMid.Token(1, true);
				bool bNotFound = false;

				// If we're breaking or continuing from within a loop, skip all tags that aren't ENDLOOP
				if ((bLoopCont || bLoopBreak) && !sAction.Equals("ENDLOOP")) {
					continue;
				}

				if (!uSkip) {
					if (sAction.Equals("INC")) {
						if (!Print(ExpandFile(sArgs, true), oOut)) {
							DEBUG("Unable to print INC'd file [" + sArgs + "]");
							return false;
						}
					} else if (sAction.Equals("SETOPTION")) {
						m_spOptions->Parse(sArgs);
					} else if (sAction.Equals("ADDROW")) {
						CString sLoopName = sArgs.Token(0);
						MCString msRow;

						if (sArgs.Token(1, true, " ").OptionSplit(msRow)) {
							CTemplate& NewRow = AddRow(sLoopName);

							for (MCString::iterator it = msRow.begin(); it != msRow.end(); ++it) {
								NewRow[it->first] = it->second;
							}
						}
					} else if (sAction.Equals("SET")) {
						CString sName = sArgs.Token(0);
						CString sValue = sArgs.Token(1, true);

						(*this)[sName] = sValue;
					} else if (sAction.Equals("JOIN")) {
						VCString vsArgs;
						//sArgs.Split(" ", vsArgs, false, "\"", "\"");
						sArgs.QuoteSplit(vsArgs);

						if (vsArgs.size() > 1) {
							CString sDelim = vsArgs[0];
							bool bFoundOne = false;
							CString::EEscape eEscape = CString::EASCII;

							for (unsigned int a = 1; a < vsArgs.size(); a++) {
								const CString& sArg = vsArgs[a];

								if (sArg.Equals("ESC=", false, 4)) {
									eEscape = CString::ToEscape(sArg.LeftChomp_n(4));
								} else {
									CString sValue = GetValue(sArg);

									if (!sValue.empty()) {
										if (bFoundOne) {
											sOutput += sDelim;
										}

										sOutput += sValue.Escape_n(eEscape);
										bFoundOne = true;
									}
								}
							}
						}
					} else if (sAction.Equals("SETBLOCK")) {
						sSetBlockVar = sArgs;
						bInSetBlock = true;
					} else if (sAction.Equals("EXPAND")) {
						sOutput += ExpandFile(sArgs, true);
					} else if (sAction.Equals("VAR")) {
						sOutput += GetValue(sArgs);
					} else if (sAction.Equals("LT")) {
						sOutput += "<?";
					} else if (sAction.Equals("GT")) {
						sOutput += "?>";
					} else if (sAction.Equals("CONTINUE")) {
						CTemplateLoopContext* pContext = GetCurLoopContext();

						if (pContext) {
							uSkip++;
							bLoopCont = true;

							break;
						} else {
							DEBUG("[" + sFileName + ":" + CString(uCurPos - iPos2 -4) + "] <? CONTINUE ?> must be used inside of a loop!");
						}
					} else if (sAction.Equals("BREAK")) {
						// break from loop
						CTemplateLoopContext* pContext = GetCurLoopContext();

						if (pContext) {
							uSkip++;
							bLoopBreak = true;

							break;
						} else {
							DEBUG("[" + sFileName + ":" + CString(uCurPos - iPos2 -4) + "] <? BREAK ?> must be used inside of a loop!");
						}
					} else if (sAction.Equals("EXIT")) {
						bExit = true;
					} else if (sAction.Equals("DEBUG")) {
						DEBUG("CTemplate DEBUG [" + sFileName + "@" + CString(uCurPos - iPos2 -4) + "b] -> [" + sArgs + "]");
					} else if (sAction.Equals("LOOP")) {
						CTemplateLoopContext* pContext = GetCurLoopContext();

						if (!pContext || pContext->GetFilePosition() != uCurPos) {
							// we are at a brand new loop (be it new or a first pass at an inner loop)

							CString sLoopName = sArgs.Token(0);
							bool bReverse = (sArgs.Token(1).Equals("REVERSE"));
							bool bSort = (sArgs.Token(1).Left(4).Equals("SORT"));
							vector<CTemplate*>* pvLoop = GetLoop(sLoopName);

							if (bSort && pvLoop != NULL &&  pvLoop->size() > 1) {
								CString sKey;

								if(sArgs.Token(1).TrimPrefix_n("SORT").Left(4).Equals("ASC=")) {
									sKey = sArgs.Token(1).TrimPrefix_n("SORTASC=");
								} else if(sArgs.Token(1).TrimPrefix_n("SORT").Left(5).Equals("DESC=")) {
									sKey = sArgs.Token(1).TrimPrefix_n("SORTDESC=");
									bReverse = true;
								}

								if (!sKey.empty()) {
									std::sort(pvLoop->begin(), pvLoop->end(), CLoopSorter(sKey));
								}
							}

							if (pvLoop) {
								// If we found data for this loop, add it to our context vector
								//unsigned long uBeforeLoopTag = uCurPos - iPos2 - 4;
								unsigned long uAfterLoopTag = uCurPos;

								for (CString::size_type t = 0; t < sLine.size(); t++) {
									char c = sLine[t];
									if (c == '\r' || c == '\n') {
										uAfterLoopTag++;
									} else {
										break;
									}
								}

								m_vLoopContexts.push_back(new CTemplateLoopContext(uAfterLoopTag, sLoopName, bReverse, pvLoop));
							} else {  // If we don't have data, just skip this loop and everything inside
								uSkip++;
							}
						}
					} else if (sAction.Equals("IF")) {
						if (ValidIf(sArgs)) {
							uNestedIfs++;
							bValidLastIf = true;
						} else {
							uSkip++;
							bValidLastIf = false;
						}
					} else if (sAction.Equals("REM")) {
						uSkip++;
					} else {
						bNotFound = true;
					}
				} else if (sAction.Equals("REM")) {
					uSkip++;
				} else if (sAction.Equals("IF")) {
					uSkip++;
				} else if (sAction.Equals("LOOP")) {
					uSkip++;
				}

				if (sAction.Equals("ENDIF")) {
					if (uSkip) {
						uSkip--;
					} else {
						uNestedIfs--;
					}
				} else if (sAction.Equals("ENDREM")) {
					if (uSkip) {
						uSkip--;
					}
				} else if (sAction.Equals("ENDSETBLOCK")) {
					bInSetBlock = false;
					sSetBlockVar = "";
				} else if (sAction.Equals("ENDLOOP")) {
					if (bLoopCont && uSkip == 1) {
						uSkip--;
						bLoopCont = false;
					}

					if (bLoopBreak && uSkip == 1) {
						uSkip--;
					}

					if (uSkip) {
						uSkip--;
					} else {
						// We are at the end of the loop so we need to inc the index
						CTemplateLoopContext* pContext = GetCurLoopContext();

						if (pContext) {
							pContext->IncRowIndex();

							// If we didn't go out of bounds we need to seek back to the top of our loop
							if (!bLoopBreak && pContext->GetCurRow()) {
								uCurPos = pContext->GetFilePosition();
								uFilePos = uCurPos;
								uLineSize = 0;

								File.Seek(uCurPos);
								bBroke = true;

								if (!sOutput.Trim_n().empty()) {
									pContext->SetHasData();
								}

								break;
							} else {
								if (sOutput.Trim_n().empty()) {
									sOutput.clear();
								}

								bTmplLoopHasData = pContext->HasData();
								DelCurLoopContext();
								bLoopBreak = false;
							}
						}
					}
				} else if (sAction.Equals("ELSE")) {
					if (!bValidLastIf && uSkip == 1) {
						CString sArg = sArgs.Token(0);

						if (sArg.empty() || (sArg.Equals("IF") && ValidIf(sArgs.Token(1, true)))) {
							uSkip = 0;
							bValidLastIf = true;
						}
					} else if (!uSkip) {
						uSkip = 1;
					}
				} else if (bNotFound) {
					// Unknown tag that isn't being skipped...
					vector<CSmartPtr<CTemplateTagHandler> >& vspTagHandlers = GetTagHandlers();

					if (!vspTagHandlers.empty()) { // @todo this should go up to the top to grab handlers
						CTemplate* pTmpl = GetCurTemplate();
						CString sCustomOutput;

						for (unsigned int j = 0; j < vspTagHandlers.size(); j++) {
							CSmartPtr<CTemplateTagHandler> spTagHandler = vspTagHandlers[j];

							if (spTagHandler->HandleTag(*pTmpl, sAction, sArgs, sCustomOutput)) {
								sOutput += sCustomOutput;
								bNotFound = false;
								break;
							}
						}

						if (bNotFound) {
							DEBUG("Unknown/Unhandled tag [" + sAction + "]");
						}
					}
				}

				continue;
			}

			DEBUG("Malformed tag on line " + CString(uLineNum) + " of [" << File.GetLongName() + "]");
			DEBUG("--------------- [" + sLine + "]");
		}

		if (!bBroke) {
			uFilePos += uLineSize;

			if (!uSkip) {
				sOutput += sLine;
			}
		}

		if (!bFoundATag || bTmplLoopHasData || sOutput.find_first_not_of(" \t\r\n") != CString::npos) {
			if (bInSetBlock) {
				CString sName = sSetBlockVar.Token(0);
				//CString sValue = sSetBlockVar.Token(1, true);
				(*this)[sName] += sOutput;
			} else {
				oOut << sOutput;
			}
		}

		if (bExit) {
			break;
		}
	}

	oOut.flush();

	return true;
}
static CString StripHTML(const CString& sFrom)
{
	CString sResult = sFrom;

	// remove tags:
	CString::size_type pos = sResult.find('<');

	while(pos != CString::npos)
	{
		CString::size_type endPos = sResult.find('>', pos);

		if(endPos != CString::npos)
		{
			sResult.erase(pos, endPos - pos + 1);
			pos = sResult.find('<', pos);
		}
		else
		{
			sResult.erase(pos);
			break;
		}
	}

	// remove stupid legay HTML entities:
	pos = sResult.find('&');

	while(pos != CString::npos)
	{
		CString::size_type endPos = sResult.find(';', pos);

		if(endPos != CString::npos)
		{
			bool found = false;

			for(unsigned int c = 0; c < 256; c++)
			{
				if(g_szHTMLescapes[c] && !strncasecmp(g_szHTMLescapes[c], (char*)(sResult.c_str() + pos), endPos - pos + 1))
				{
					sResult.erase(pos, endPos - pos + 1);
					sResult.insert(pos, 1, (char)c);
					found = true;
					break;
				}
			}

			if(!found && sResult[pos + 1] != '#')
				sResult.erase(pos, endPos - pos + 1);

			pos = sResult.find('&', pos + 1);
		}
		else
			break;
	}

	// remove numerical and XML entities:
	sResult = sResult.Escape_n(CString::EHTML, CString::EASCII);

	// because entitiy decoding is being done in two steps,
	// this screws up in certain situations, e.g. &#38;gt;
	// produces '>' instead of '&gt;' ... but whatever.


	// normalize whitespace:
	RE("\\s+").GlobalReplace(" ", &sResult);
	sResult.Trim();

	return sResult;
}