0
  +   laeJi@pe1hm_I|+ ?     #include <TestSupport.h>
#include <boost/foreach.hpp>
#include <boost/bind/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/thread.hpp>
#include <oxt/system_calls.hpp>
#include <limits>
#include <BackgroundEventLoop.h>
#include <ServerKit/HttpServer.h>
#include <LoggingKit/LoggingKit.h>
#include <FileDescriptor.h>
#include <Utils.h>
#include <IOTools/IOUtils.h>
#include <IOTools/BufferedIO.h>

using namespace Passenger;
using namespace Passenger::ServerKit;
using namespace Passenger::MemoryKit;
using namespace std;
using namespace oxt;

namespace tut {
	class MyRequest: public BaseHttpRequest {
	public:
		string body;
		bool testingHalfClose;

		DEFINE_SERVER_KIT_BASE_HTTP_REQUEST_FOOTER(MyRequest);
	};

	class MyClient: public BaseHttpClient<MyRequest> {
	public:
		MyClient(void *server)
			: BaseHttpClient<MyRequest>(server)
		{
			SERVER_KIT_BASE_HTTP_CLIENT_INIT();
		}

		DEFINE_SERVER_KIT_BASE_HTTP_CLIENT_FOOTER(MyClient, MyRequest);
	};

	class MyServer: public HttpServer<MyServer, MyClient> {
	private:
		typedef HttpServer<MyServer, MyClient> ParentClass;

		void testRequest(MyClient *client, MyRequest *req) {
			HeaderTable headers;
			const unsigned int BUFSIZE = 128;
			char *response = (char *) psg_pnalloc(req->pool, BUFSIZE);
			char *pos = response;
			const char *end = response + BUFSIZE;
			const LString *value;
			const LString::Part *part;

			headers.insert(req->pool, "date", "Thu, 11 Sep 2014 12:54:09 GMT");
			headers.insert(req->pool, "content-type", "text/plain");

			pos = appendData(pos, end, "hello ");
			part = req->path.start;
			while (part != NULL) {
				pos = appendData(pos, end, part->data, part->size);
				part = part->next;
			}

			value = req->headers.lookup("foo");
			if (value != NULL) {
				pos = appendData(pos, end, "\nFoo: ");
				part = value->start;
				while (part != NULL) {
					pos = appendData(pos, end, part->data, part->size);
					part = part->next;
				}
			}

			value = req->secureHeaders.lookup("!~Secure");
			if (value != NULL) {
				pos = appendData(pos, end, "\nSecure: ");
				part = value->start;
				while (part != NULL) {
					pos = appendData(pos, end, part->data, part->size);
					part = part->next;
				}
			}

			writeSimpleResponse(client, 200, &headers,
				StaticString(response, pos - response));
			endRequest(&client, &req);
		}

		void testBody(MyClient *client, MyRequest *req) {
			if (!req->hasBody() && !req->upgraded()) {
				writeSimpleResponse(client, 422, NULL, "Body required");
				if (!req->ended()) {
					endRequest(&client, &req);
				}
			}
		}

		void testBodyStop(MyClient *client, MyRequest *req) {
			if (!req->hasBody() && !req->upgraded()) {
				writeSimpleResponse(client, 422, NULL, "Body required");
				if (!req->ended()) {
					endRequest(&client, &req);
				}
			} else {
				refRequest(req, __FILE__, __LINE__);
				req->bodyChannel.stop();
				requestsWaitingToStartAcceptingBody.push_back(req);
				// Continues in startAcceptingBody()
			}
		}

		void startAcceptingBody(MyClient *client, MyRequest *req) {
			req->bodyChannel.start();
			// Continues in onRequestBody()
		}

		void testLargeResponse(MyClient *client, MyRequest *req) {
			const LString *value = req->headers.lookup("size");
			value = psg_lstr_make_contiguous(value, req->pool);
			unsigned int size = stringToUint(StaticString(value->start->data, value->size));
			char *body = (char *) psg_pnalloc(req->pool, size);
			memset(body, 'x', size);
			writeSimpleResponse(client, 200, NULL, StaticString(body, size));
			if (!req->ended()) {
				endRequest(&client, &req);
			}
		}

		void testPath(MyClient *client, MyRequest *req) {
			if (req->path.start->next == NULL) {
				writeSimpleResponse(client, 200, NULL, "Contiguous: 1");
			} else {
				writeSimpleResponse(client, 500, NULL, "Contiguous: 0");
			}
			if (!req->ended()) {
				endRequest(&client, &req);
			}
		}

		void testHalfClose(MyClient *client, MyRequest *req) {
			req->testingHalfClose = true;
			// Continues in onR