Пример #1
0
LightSpeed::JSON::PNode createArrayFromSet(LightSpeed::JSON::IFactory &factory, ConstStrA text, char sep) {
	LightSpeed::JSON::PNode arr = factory.newArray();
	if (text.empty()) return arr;

	for (ConstStrA::SplitIterator iter = text.split(sep);iter.hasItems();) {
		ConstStrA name = iter.getNext();
		if (!name.empty()) {
			arr->add(factory.newValue(name));
		}
	}
	return arr;
}
Пример #2
0
void HttpClient::proxyConnect(PNetworkStream stream, ConstStrA host, ConstStrA authorization) {
	if (host.find(':') == naturalNull) {
		return proxyConnect(stream,StringA(host+ConstStrA(":443")),authorization);
	}
	PNetworkStream nstream = new BufferedNetworkStream(stream);

	HttpRequest req(stream.get(), host, mCONNECT, !useHTTP10);
	if (!authorization.empty()) {
		req.setHeader(fldProxyAuthorization,authorization);
	}
	req.closeOutput();

	class ResponseResult: public IHttpResponseCB {
	public:
		virtual void storeStatus(natural statusCode, ConstStrA statusMessage) {
			status = statusCode;
			statusMsg.append(statusMessage);
		}
		virtual void storeHeaderLine(ConstStrA, ConstStrA) {

		}

		natural status;
		AutoArray<char, SmallAlloc<32> > statusMsg;
	};

	ResponseResult res;

	HttpResponse resp(stream.get(),res,HttpResponse::readHeadersNow);
	if (status != 200)
		throw HttpStatusException(THISLOCATION,host,res.status, res.statusMsg);
}
Пример #3
0
	std::pair<PExprNode, FilePath> FileCompiler::loadCode(ExprLocation loc, ConstStrA name)
	{


		FilePath p = loc.getFileName();
		if (p.getPath().empty()) p = FilePath(ConstStrW(L"."), true);
		for (ConstStrA::SplitIterator iter = name.split('/'); iter.hasItems();) {
			ConstStrA part = iter.getNext();
			if (part.empty()) {
				continue;
			}
			else if (part == "..") {
				p = p / parent;
			}
			else {
				p = p / part;
			}			
		}

		const PExprNode *code = codeCache.find(p);
		PExprNode out;
		if (code) out = *code;
		else {
			out = compileFile(p);
			codeCache(p, out);
		}
		return std::make_pair(out, p);

	}
Пример #4
0
natural Server::onGET(BredyHttpSrv::IHttpRequest& req, ConstStrA vpath) {
	if (vpath.empty() && req.getHeaderField(req.fldUpgrade) == "websocket" ) {
		if (!wsenabled) return stForbidden;
		else return req.forwardRequestTo(&wsHandler,vpath);
	} else {
		return HttpHandler::onGET(req,vpath);
	}
}
Пример #5
0
void HttpReqImpl::status(natural code, ConstStrA msg) {
	if (bHeaderSent)
		throw ErrorMessageException(THISLOCATION, "Headers already sent");

	statusCode = code;
	if (msg.empty())
		msg = getStatusMessage(statusCode);

	statusMsg = responseHdrPool.add(msg);
}
Пример #6
0
void HttpReqImpl::errorPage(natural code, ConstStrA msg, ConstStrA expl) {
	if (!bHeaderSent) {
		if (msg.empty()) msg = getStatusMessage(code);
		SeqFileOutput f(this);
		if (msg.empty()) msg = getStatusMessage(code);
		PrintTextA print(f);
		//clear some headers - they can damage output
		//delete content length - because we will show different page
		responseHdrs.erase(getHeaderFieldName(fldContentLength));
		//delete transfer encoding - because we need simplest encoding
		responseHdrs.erase(getHeaderFieldName(fldTransferEncoding));
		//delete content type - because we will set to text/html
		responseHdrs.erase(getHeaderFieldName(fldContentType));
		//delete eTag - don't store eTag with an error page
		responseHdrs.erase(getHeaderFieldName(fldETag));
		//delete lastModified - don't store error page
		responseHdrs.erase(getHeaderFieldName(fldLastModified));
		status(code,msg);
		//set new content type
		header(fldContentType,"text/html");

		if (code == 204 || code == 304) {
			//set ContentLength to zero even if it is not necesery, some clients can have issue
			header(fldContentLength,"0");
			sendHeaders();
			return;
		} else {
			closeConn = true;
		}
		print("<html><head><title>%1 %2</title></head><body><h1>%1 %2</h1>")
				<< code << msg;
		if (!expl.empty()) print("<pre>%1</pre>")<< expl;
		print("<hr>");
		print("<small><em>Powered by Bredy's JsonRpcServer - C++ http & jsonrpc server - <a href=\"https://github.com/ondra-novak/jsonrpcserver\">sources available</a></em></small>");
		print("</body></html>");
	}
	else {
		closeConn = true;
	}
}
Пример #7
0
LightSpeed::StringA dbOrderFromJSON(const LightSpeed::JSON::INode &nd, ConstStrA allowedSet) {
	using namespace LightSpeed;
	AutoArray<char, SmallAlloc<256> > buff;
	for (natural i = 0; i < nd.getEntryCount();i++) {
		ConstStrA fld = nd[i].getStringUtf8();
		if (fld.empty() || fld == ConstStrA('^') || fld.find('`') != naturalNull)
			  throw ErrorMessageException(THISLOCATION, "Unacceptable field name");
		if (i) buff.append(ConstStrA(", "));
		if (fld[0] == '^') {
			ConstStrA trans = findInAllowedSet(fld.offset(1),allowedSet);
			if (!trans.empty()) {
				appendField(trans, buff);
				buff.append(ConstStrA(" DESC"));
			}
		} else {
			ConstStrA trans = findInAllowedSet(fld,allowedSet);
			if (!trans.empty()) {
				appendField(trans, buff);
				buff.append(ConstStrA(" ASC"));
			}
		}
	}
	return ConstStrA(buff);
}
Пример #8
0
ITCPServerConnHandler::Command  HttpReqImpl::finishReadHeader() {


	TextParser<char,StaticAlloc<256> > parser;

	//open output and input, we need stream to show error pages
	outputClosed = false;
	inputClosed = false;


	isHeadMethod = ConstStrA(method) == "HEAD";
	closeConn = httpMinVer == 0;

	//check connection
	HeaderValue strconn = getHeaderField(fldConnection);
	if (strconn.defined) {
		if (strconn == "close") closeConn = true;
	}


	//check content length
	HeaderValue strsize = getHeaderField(fldContentLength);
	if (strsize.defined && parser(" %u1 ", strsize)) {
		remainPostData = parser[1];
	} else {
		remainPostData = 0;
	}

	//check chunked POST
	HeaderValue strchunked = getHeaderField(fldTransferEncoding);
	if (strchunked.defined != 0 && strchunked == "chunked") {
		chunkedPost = true;
		remainPostData = 0; //remainPostData is used to count chunks
	} else {
		chunkedPost = false;
	}

	//check expectation for 100-continue
	HeaderValue strexpect = getHeaderField(fldExpect);
	if (strexpect.defined != 0) {
		if (strexpect == "100-continue" || strexpect == "100-Continue") {
			bNeedContinue = true;
		} else {
			return errorPageKA(417);
		}
	} else {
		bNeedContinue = false;
	}

	//check host
	ConstStrA vpath = path;
	host = getHeaderField(fldHost);
	if (!mapHost(host, vpath)) {
		return errorPageKA(404);
	}

	if (vpath.empty()) {
		redirect("+/");
		return processHandlerResponse(0);
	}


	//find handler
	IHttpHandler *h;
	curHandler = nil;
	natural res = callHandler( vpath, &h);
	if (h == 0) return errorPageKA(404);
	if (curHandler == nil) curHandler = h; //need this to correctly handle forward function
	return processHandlerResponse(res);
}
Пример #9
0
ITCPServerConnHandler::Command  HttpReqImpl::readHeader() {

	try {

		AutoArray<char, SmallAlloc<8192> > linebuff;

		NStream::Buffer &buffer = inout->getBuffer();
		natural fetched = buffer.fetch();
		if (fetched == 0) {
			errorPage(413,ConstStrA(),"Header is too large");
			return ITCPServerConnHandler::cmdRemove;
		}
		natural pos = buffer.lookup(ConstBin("\r\n"),fetched);
		while (pos != naturalNull) {

			linebuff.resize(pos+2);
			buffer.read(linebuff.data(),pos+2);
			ConstStrA line = linebuff.head(pos);

			if (method.empty()) {
				if (pos == 0) return ITCPServerConnHandler::cmdWaitRead;

				reqBeginTime = TimeStamp::now();
				reportDuration = true;

				cropWhite(line);
				ConstStrA::SplitIterator splt = line.split(' ');
				method = hdrPool.add(ConstStrA(splt.getNext()));
				path = hdrPool.add(ConstStrA(splt.getNext()));
				while (path.empty()) path = hdrPool.add(ConstStrA(splt.getNext()));
				protocol = hdrPool.add(ConstStrA(splt.getNext()));
				while (protocol.empty()) protocol = hdrPool.add(ConstStrA(splt.getNext()));
				//parse some fields
				TextParser<char,StaticAlloc<256> > parser;

				//check http version
				if (parser("HTTP/%u1.%u2",protocol)) {
						httpMajVer = (unsigned short)((natural)parser[1]);
						httpMinVer = (unsigned short)((natural)parser[2]);
						if (httpMajVer != 1 || (httpMinVer != 0 && httpMinVer != 1))
							return errorPageKA(505);
						useHTTP11(httpMinVer == 1);
				} else {
					return errorPageKA(400,StringA(ConstStrA("Unknown protocol: ")+ protocol));
				}
			} else if (line.empty()) {
				return finishReadHeader();
			} else {

				natural dblcolon = line.find(':');
				if (dblcolon == naturalNull) {
					errorPage(400,ConstStrA(),"line");
					return ITCPServerConnHandler::cmdRemove;
				}
				ConstStrA field = line.head(dblcolon);
				ConstStrA value = line.offset(dblcolon+1);
				cropWhite(field);
				cropWhite(value);
				requestHdrs.insert(hdrPool.add(field),hdrPool.add(value));
			}
			pos = buffer.lookup(ConstBin("\r\n"));
		}
		return ITCPServerConnHandler::cmdWaitRead;
	} catch (AllocatorLimitException &) {
		errorPage(413,ConstStrA(),"Header is too large (4096 bytes)");
		return ITCPServerConnHandler::cmdRemove;
	}
}
Пример #10
0
void HttpReqImpl::sendHeaders() {
	if (bHeaderSent)
		return;

	if (bNeedContinue) {
		remainPostData = 0;
		chunkedPost = false;
	}
	bNeedContinue = false;

	bool hasServer = false;
	bool hasContentType = false;
	bool hasTransfEnc = false;
	bool hasConnection = false;
	bool hasLength = false;
	bool hasDate = false;
	static ConstStrA contentTypeKey = getHeaderFieldName(fldContentType);
	static ConstStrA serverKey = getHeaderFieldName(fldServer);
	static ConstStrA transfEnc = getHeaderFieldName(fldTransferEncoding);
	static ConstStrA connectionStr = getHeaderFieldName(fldConnection);
	static ConstStrA contenLenStr = getHeaderFieldName(fldContentLength);
	static ConstStrA dateStr = getHeaderFieldName(fldDate);
	ConstStrA statusMsgStr = this->statusMsg;
	if (statusMsgStr.empty())
		statusMsgStr = getStatusMessage(statusCode);


	PrintTextA print(*inout);
	print.setNL("\r\n");
	print("HTTP/%1.%2 %3 %4\n") << httpMajVer << httpMinVer << statusCode
			<< statusMsgStr;

	if (statusCode == 101) {
		hasTransfEnc = hasConnection = hasContentType = true;
		useChunked = false;
		remainPostData = naturalNull;
		switchedProtocol = true;
		TimeStamp reqEndTime = TimeStamp::now();
		natural reqTime = (reqEndTime - reqBeginTime).getMilis();
		logRequest(reqTime);
	}

	for (HeaderMap::Iterator iter = responseHdrs.getFwIter(); iter.hasItems();) {
		const HeaderMap::Entity hdrPair = iter.getNext();
		if (!hasContentType && hdrPair.key == contentTypeKey)
			hasContentType = true;

		if (!hasServer && hdrPair.key == serverKey)
			hasServer = true;

		if (!hasTransfEnc && hdrPair.key == transfEnc)
			hasTransfEnc = !(useChunked && hdrPair.value == ConstStrA("chunked"));

		if (!hasConnection && hdrPair.key == connectionStr)
			hasConnection = true;

		if (!hasDate && hdrPair.key == dateStr)
			hasDate = true;

		if (!hasLength && hdrPair.key == contenLenStr) {
			hasLength = true;
		}

		print("%1: %2\n") << ConstStrA(hdrPair.key) << ConstStrA(hdrPair.value);
	}
	if (!hasContentType)
		print("%1: %2\n") << contentTypeKey << "text/html;charset=UTF-8";

	if (!hasServer)
		print("%1: %2\n") << serverKey << serverIdent;

	if (hasLength) {
		useChunked = false;
	}

	if (!hasDate) {
		TimeStamp::RFC1123Time datenow = TimeStamp::now().asRFC1123Time();
		print("%1: %2\n") << dateStr << ConstStrA(datenow);
	}

	if (!hasTransfEnc && useChunked && !closeConn)
		print("%1: %2\n") << transfEnc << "chunked";
	else
		useChunked = false;

	if (!hasConnection && closeConn)
		print("%1: %2\n") << connectionStr << "close";

	print("\n");

/*	LogObject(THISLOCATION).progress("%7 - %3 %4 HTTP/%1.%2 %5 %6")
		<< httpMajVer << httpMajVer << ConstStrA(method)
		<< ConstStrA(path) << statusCode << statusMsgStr
		<< getIfc<IHttpPeerInfo>().getPeerRealAddr();*/

	responseHdrs.clear();
	//for code 100 or 101, additional header will be next
	if (statusCode == 100) {
		//set status code 200 to simply processing reply (handler don't need to reset 100 status
		statusCode = 200;
		//unset message
		this->statusMsg = HdrStr();
		//now, handler can exit function with status 100 - when data arrives, onData will be called
	} else {
		//header sent, prevent sending new headers
		bHeaderSent = true;
	}
}
Пример #11
0
void HttpClient::createRequest(ConstStrA url, Method method) {

	connectionReused = false;
		TextParser<char, SmallAlloc<1024> > parser;
		if (parser("http%(?)[s]1://%(*)*2%%[a-zA-Z0-9-_.:]3/%(*)4",url)) {
			ConstStrA s = parser[1].str();
			ConstStrA auth = parser[2].str();
			ConstStrA domain_port = parser[3].str();
			ConstStrA path = parser[4].str();
			path = url.tail(path.length()+1);
			if (!s.empty() && s != "s")
				throw InvalidUrlException(THISLOCATION,url,"unknown protocol");
			if (!auth.empty() && s.tail(1)[0] != '@')
				throw InvalidUrlException(THISLOCATION,url,"auth need '@' as separator");
			if (domain_port.tail(1)[0] == ':')
				throw InvalidUrlException(THISLOCATION,url,"missing port number");

			bool tls = !s.empty();
			IHttpProxyProvider::Result proxyInfo;
			if (proxyProvider) {
				proxyInfo = proxyProvider->getProxy(domain_port);
			}

			if (canReuseConnection(domain_port, tls)) {
				try {
					response->skipRemainBody();
					connectionReused = true;
				} catch (const NetworkException &) {
					response = nil;
					nstream = nil;
				}
			}

			if (!connectionReused) {
				if (tls) {
					if (httpsProvider == 0) {
						throw InvalidUrlException(THISLOCATION,url,"Https is not configured");
					}
					PNetworkStream stream;
					if (proxyInfo.defined) {
						stream = connectSite(proxyInfo.proxyAddr,8080);
						proxyConnect(stream, domain_port, proxyInfo.authorization);
					} else {
						stream = connectSite(domain_port, 443);
					}
					stream = httpsProvider->connectTLS(stream,domain_port);
					nstream = new BufferedNetworkStream(stream);
					currentDomain = domain_port;
					currentTls = true;
				} else {
					if (proxyInfo.defined) {
						PNetworkStream stream;
						stream = connectSite(proxyInfo.proxyAddr,8080);
						nstream = new BufferedNetworkStream(stream);
						path = url;
						currentDomain = proxyInfo.proxyAddr;
					} else {
						PNetworkStream stream;
						stream = connectSite(domain_port,80);
						nstream = new BufferedNetworkStream(stream);
						currentDomain = domain_port;
					}
				}
			}
			response = nil;
			request = new(pool) HttpRequest(nstream.get(),path,method,!useHTTP10);
			if (proxyInfo.defined && !tls && !proxyInfo.authorization.empty()) {
				request->setHeader(fldProxyAuthorization, proxyInfo.authorization);
			}
			request->setHeader(fldHost, domain_port);
			request->setHeader(fldUserAgent, userAgent);
			if (keepAlive == false) {
				request->setHeader(fldConnection,"close");
			} else if (useHTTP10) {
				request->setHeader(fldConnection,"keep-alive");
			}

		} else {
			throw InvalidUrlException(THISLOCATION,url,"Parser rejected");
		}
}