Beispiel #1
0
bool WinHttpStream::enumHeaders( IEnumHeaders &enumHdr )
{
	setState(stReadResponse);

	AutoArray<char> buffer;
	buffer.resize(1000);
	DWORD size = (DWORD)buffer.length();
	while (!HttpQueryInfoA(hHTTPConn,HTTP_QUERY_RAW_HEADERS,
		buffer.data(),&size,0)) {
			DWORD res = GetLastError();
			if (res == ERROR_INSUFFICIENT_BUFFER) {
				buffer.resize(size);
			} else {
				throw ErrNoWithDescException(THISLOCATION,GetLastError(),
					"Cannot retrieve headers from the request");
			}
	}
	buffer.resize(size);

	AutoArray<char>::SplitIterator iter=buffer.split((char)0);
	TextParser<char> parser;
	while (iter.hasItems()) {
		ConstStrA line = iter.getNext();
		if (parser("%1 : %2",line)) {
			ConstStrA field = parser[1].str();
			ConstStrA value = parser[2].str();
			if(enumHdr(field, value)) return true;
		}
	}

	return false;


}
Beispiel #2
0
	integer ServiceApp::postMessage(ConstStrA command, const Args & args, SeqFileOutput output)
	{

		if (instance->imOwner()) return onMessage(command,args,output);

		AutoArrayStream<char, StaticAlloc<65536> > buffer;
		if (args.length() > 127) return onCommandLineError(args);
		buffer.write((char)(args.length()));
		buffer.copy(command.getFwIter());
		buffer.write(0);
		for(natural i = 0, cnt = args.length();i < cnt;i++){
			buffer.copy(WideToUtf8Reader<ConstStrW::Iterator>(args[i].getFwIter()));
			buffer.write(0);
		}
		AutoArray<byte,SmallAlloc<4096> > replybuff;
		replybuff.resize(instance->getReplyMaxSize());
		natural sz = instance->request(buffer.data(), buffer.length(), replybuff.data(), replybuff.length(), timeout);
		if (sz < sizeof(integer))
			throw ErrorMessageException(THISLOCATION,String("Invalid reply"));
		else {
			integer res = *reinterpret_cast<integer *>(replybuff.data());
			ConstStrA msg(reinterpret_cast<char *>(replybuff.data()+sizeof(integer)),sz - sizeof(integer));
			output.copy(msg.getFwIter());
			return res;
		}
	}
Beispiel #3
0
StringA WinHttpStream::getReplyHeaders()
{
	setState(stReadResponse);
	AutoArray<char> buffer;
	buffer.resize(1000);
	DWORD size = (DWORD)buffer.length();
	while (!HttpQueryInfoA(hHTTPConn,HTTP_QUERY_RAW_HEADERS_CRLF,
		buffer.data(),&size,0)) {
			DWORD res = GetLastError();
			if (res == ERROR_INSUFFICIENT_BUFFER) {
				buffer.resize(size);
			} else {
				throw ErrNoWithDescException(THISLOCATION,GetLastError(),
					"Cannot retrieve headers from the request");
			}
	}
	buffer.resize(size);
	return buffer;
}
Beispiel #4
0
	bool ServiceApp::processRequest(const void *request)
	{
		const char *p = reinterpret_cast<const char*>(request);
		natural count = *p++;
		ConstStrA command(p);
		p += command.length() + 1;
		AutoArray<String,StaticAlloc<256> > params;
		AutoArray<ConstStrW,StaticAlloc<256> > wparams;
		for(natural i = 0;i < count;i++){
			ConstStrA param(p);
			p += param.length() + 1;
			params.add(String(param));
			wparams.add(ConstStrW(params[i]));
		}
		AutoArray<byte> output;
		output.resize(instance->getReplyMaxSize());
		SeqOutputBuffer fakeout(output.data() + sizeof (integer), output.length() - sizeof (integer));
		fakeout.setStaticObj();
		integer res = -1;
		bool stop = false;
		SeqFileOutput out(&fakeout);
		try {
			res = onMessage(command, wparams, out);
			stop = command == ConstStrA(stopCmd);
		}
		catch(std::exception & e){
			TextOut<SeqFileOutput> msg(out);
			msg("%1") << e.what();
			res = -1;
		}
		try {
			*reinterpret_cast<integer*>(output.data()) = res;
			instance->sendReply(output.data(), fakeout.length() + sizeof (integer));
		}
		catch(...){
		}
		return !stop;
	}
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;
	}
}
HttpResponse& HttpClient::sendRequestInternal(ConstStrA url, Method method, SeqFileInput data, const HdrItem* headers, bool wo100) {

	//for HTTP/1.0 we need to buffer request (sad)
	if (useHTTP10) {
		//create buffer
		AutoArray<byte> buffer;
		if (data.hasItems()) {
			do {
				natural pos = buffer.length();
				//reserve buffer
				buffer.resize(pos+4096);
				//read buffer
				natural sz = data.blockRead(buffer.data()+pos,4096,true);
				//adjust buffer size
				buffer.resize(pos+sz);
				//continue until end
			} while (data.hasItems());
		}
		//send request
		return sendRequest(url,method,buffer,headers);
	} else {
		//while reading from the stream, we need to ensure, that server is ready to accept our data
		//so in this case, we will use Expect: 100-continue precondition
		try {
			//create request for url
			HttpRequest &rq = createRequest(url,method);
			//we don't need to use 100-continue if connection was recently opened
			if (!connectionReused) wo100 = true;
			//set content length to infinity - this should switch to chunked
			rq.setContentLength(naturalNull);
			//load headers
			feedHeaders(rq, headers);
			//set Expect: 100-continue
			if (!wo100) rq.setHeader(fldExpect,"100-continue");
			//close headers and start body, but we must wait for response now
			rq.beginBody();
			//so create response (do not read headers)
			HttpResponse& resp = createResponse(false);
			//now wait some time to server's response.
			//because it could ignore our header, we must not wait for infinity time
			if (wo100 || nstream->wait(INetworkResource::waitForInput,10000) != INetworkResource::waitTimeout) {
				//data arrived in time - read headers
				resp.readHeaders();
				//there can other response, so if we cannot continue, return response to the caller
				if (!resp.canContinue()) {
					//check status
					if (resp.getStatus() == 417) //we got precondition failed - no worries, we can repeat the request
						//at least we know, that connection is alive
						return sendRequestInternal(url,method,data,headers,true);
					else {
						//other status is send to the caller
						return resp;
					}
				}
			}

			//until now, request could be repeated anytime for network errors
			//- because keep-alive can be closed by the server anytime during request

			//now we should prevent repeating request when network error happened
			//because we starting reading the stream
			connectionReused = false;

			//create a buffer for data
			CArray<byte, 1024> buffer;
			//open request as stream
			SeqFileOutput dout(&rq);
			//use blockcopy to copy data to the request
			dout.blockCopy(data,buffer,naturalNull);
			//close the output
			rq.closeOutput();
			//now wait for response.
			resp.waitAfterContinue(HttpResponse::readHeadersNow);

			//because we could skip waiting on 100-continue above, we need to receive it now
			//and any other such responses
			while (resp.canContinue()) {
				resp.waitAfterContinue(HttpResponse::readHeadersNow);
			}

			//return other response to the caller
			return resp;
		} catch (const NetworkException &e) {
			if (connectionReused) {
				closeConnection();
				return sendRequest(url, method, data, headers);
			} else {
				throw;
			}
		}
	}
}